fix: block prototype-polluting set paths#186
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9bf03f1370
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7be7881df4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (isPollutingKey(ref.id) || this.hasPollutingPropertyPath(ref)) { | ||
| return; |
There was a problem hiding this comment.
Preserve safe own constructor/prototype fields
When a template writes through an ordinary data object that has an own field named constructor or prototype (for example #set($model.constructor.name = 'Car') with { model: { constructor: {} } }), this early check skips the whole assignment even though it never traverses Object.prototype; the dangerous case is the inherited constructor.prototype chain, not every data property with these names. This silently drops valid template updates for contexts that legitimately expose those keys.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
velocity.js/src/compile/set.ts
Line 59 in 09e050d
For dynamic index paths such as #set($key = "__proto__") #set($target[$key].polluted = $markEvaluated()), the new static guard does not run because the path segment is an index, so the RHS is evaluated here before the traversal reaches the isPollutingKey(key) check and skips the write. That means application callbacks or other RHS side effects still run for prototype-polluting paths, unlike the static __proto__ case covered by the new test; validate/resolve the dynamic path before evaluating the assigned value or defer RHS evaluation until after the key check.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Closed in favor of #188, which reworks the fix from a path-resolution model instead of the earlier broad key denylist. |
Motivation
#setto write properties like__proto__,constructor, orprototypeinto object paths.#setimplementation resolved and wrote path segments without guarding prototype-polluting keys, allowing modifications toObject.prototypein the running process.Description
POLLUTING_KEYS = new Set(['__proto__','constructor','prototype'])and helperisPollutingKeyinsrc/compile/set.tsto detect dangerous keys.#setwrites when the root reference (ref.id) or any resolved path segment matches a polluting key to avoid writing into prototype properties.test/set.test.tsto cover__proto__,constructor.prototype, and index-based"__proto__"pollution attempts.src/compile/set.tsandtest/set.test.ts.Testing
npm run lintand it completed successfully.npm test -- --runInBandand all test suites passed (175 passed, 175 total), including the new prototype protection tests.npm run test:buildand the build + build-tests succeeded.Codex Task