fix(scripts): guard validate-i18n against prototype pollution#966
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
All contributors have signed the CLA ✍️ ✅ Posted by the CLA bot. |
Greptile SummaryThis PR guards
Confidence Score: 3/5The fix correctly hardens The change only partially addresses the vulnerability it targets. scripts/validate-i18n.mjs — specifically the
|
| Filename | Overview |
|---|---|
| scripts/validate-i18n.mjs | Adds UNSAFE_KEYS guard to setNestedValue to fix prototype-pollution CodeQL alert, but the symmetric deleteNestedValue function was not hardened with the same guard, leaving the same class of traversal risk open. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[cmdValidate called with fix=true] --> B[Iterate missing paths from en.json]
B --> C[setNestedValue locale, path, null]
C --> D{Any segment in UNSAFE_KEYS?}
D -- Yes --> E[throw Error — GUARDED ✓]
D -- No --> F[Traverse & assign value]
A --> G[Iterate extra paths from locale JSON]
G --> H[deleteNestedValue locale, path]
H --> I{Any segment in UNSAFE_KEYS?}
I -- No check --> J[stack push via parts_i]
J --> K{parts_i == __proto__ ?}
K -- Yes --> L[Pushes prototype object onto stack]
L --> M[delete from prototype chain ⚠️ NOT GUARDED]
K -- No --> N[Normal traversal & delete]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[cmdValidate called with fix=true] --> B[Iterate missing paths from en.json]
B --> C[setNestedValue locale, path, null]
C --> D{Any segment in UNSAFE_KEYS?}
D -- Yes --> E[throw Error — GUARDED ✓]
D -- No --> F[Traverse & assign value]
A --> G[Iterate extra paths from locale JSON]
G --> H[deleteNestedValue locale, path]
H --> I{Any segment in UNSAFE_KEYS?}
I -- No check --> J[stack push via parts_i]
J --> K{parts_i == __proto__ ?}
K -- Yes --> L[Pushes prototype object onto stack]
L --> M[delete from prototype chain ⚠️ NOT GUARDED]
K -- No --> N[Normal traversal & delete]
Comments Outside Diff (1)
-
scripts/validate-i18n.mjs, line 55-69 (link)deleteNestedValuemissing the same UNSAFE_KEYS guarddeleteNestedValuetraverses the same dotted path withstack[i][parts[i]]but never checks againstUNSAFE_KEYS. If a path segment is__proto__,stack[i]["__proto__"]resolves to the prototype object rather than an own property, pushing it ontostack. The subsequentdelete stack[stack.length - 1][parts[parts.length - 1]]then operates on the prototype — the symmetric risk to whatsetNestedValuewas just hardened against. The caller incmdValidatefeeds itextrapaths derived from locale JSON files, so a crafted key name would reach this code path.
Reviews (1): Last reviewed commit: "fix(scripts): guard validate-i18n setNes..." | Re-trigger Greptile
7d102bf to
f8a5d2f
Compare
…lution setNestedValue and deleteNestedValue built object keys from a dotted path, so a segment like `__proto__`/`constructor`/`prototype` could mutate the prototype chain instead of the target object. Both now reject such segments up front. deleteNestedValue matters most: its paths come from locale-file data (getLeafPaths), i.e. untrusted input. Resolves CodeQL js/prototype-pollution-utility. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f8a5d2f to
914bd7d
Compare
|
Greptile triage — the
|
|
🚀 Released in v1.9.0 |
Resolves the medium-severity CodeQL js/prototype-pollution-utility alert in
scripts/validate-i18n.mjs.setNestedValue(and its siblingdeleteNestedValue) built object keys from a dotted path, so a segment like__proto__,constructor, orprototypecould mutate the prototype chain instead of the target object. Both now reject those segments up front.deleteNestedValuematters most: its paths come from locale-file data (getLeafPaths), i.e. untrusted input, so it's guarded for symmetry per the "check sibling sinks" rule.Verified
bun run i18n:validatestill passes for all locales and legit key paths are unaffected. Dev-tooling only, no package impact (no changeset).🤖 Generated with Claude Code