Skip to content

fix: guard AST node property lookups against prototype pollution (fixes #3414) - #3470

Open
Ayoub-glitsh wants to merge 1 commit into
pugjs:masterfrom
Ayoub-glitsh:fix/prototype-pollution-rce-gadgets
Open

fix: guard AST node property lookups against prototype pollution (fixes #3414)#3470
Ayoub-glitsh wants to merge 1 commit into
pugjs:masterfrom
Ayoub-glitsh:fix/prototype-pollution-rce-gadgets

Conversation

@Ayoub-glitsh

Copy link
Copy Markdown

Problem

Several packages accessed properties on AST node objects without verifying they were own properties. In JavaScript, obj.prop traverses the prototype chain — so if an attacker has already achieved prototype pollution elsewhere in the app, they can inject values like Object.prototype.block, .type, .val, .code, .line and escalate to RCE during template compilation.

The three PoC gadgets from #3414 all exploit this pattern:

  • Gadget 1: Object.prototype.block with a malicious Text node containing arbitrary JS in line
  • Gadget 2: Object.prototype.code with a malicious val
  • Gadget 3: Object.prototype.val injecting code into attribute generation

Fix

Guard all property accesses that influence control flow or code generation with Object.prototype.hasOwnProperty.call(node, 'prop') before reading the value.

Files changed

  • pug-walk/index.js — the most critical, used by all other packages. switch (ast.type) and all if (ast.block/alternate/consequent) checks are now guarded.
  • pug-code-gen/index.jsnode.line, node.block, tag.code, node.isInline, node.val, node.type checks guarded.
  • pug-linker/index.jsnode.type, node.call, node.mode, node.block, node.ignore, node.parents, node.textOnly checks guarded.
  • pug-filters/lib/handle-filters.jsnode.type, node.filters, node.block checks guarded.

Tests

648/650 tests pass. The 2 failures are pre-existing and unrelated — they test for old Node.js error message wording (Cannot read property vs the newer Cannot read properties) introduced in Node 16+.

Unsafe property accesses like if (node.block) or
ode.type === 'X'
traverse the prototype chain, allowing an attacker who has already
achieved prototype pollution to escalate to RCE by injecting values
such as Object.prototype.block, .type, .val, .code, .line, etc.

Fix all vulnerable lookup sites in pug-walk, pug-code-gen, pug-linker,
and pug-filters by using Object.prototype.hasOwnProperty.call() before
reading any property that influences control flow or code generation.

Fixes pugjs#3414
@rollingversions

rollingversions Bot commented Apr 29, 2026

Copy link
Copy Markdown

This PR will not result in a new version of the following packages as there are no user facing changes:

  • pug
  • pug-attrs
  • pug-code-gen
  • pug-error
  • pug-filters
  • pug-lexer
  • pug-linker
  • pug-load
  • pug-parser
  • pug-runtime
  • pug-strip-comments
  • pug-walk

Add changes to trigger a release

@Ayoub-glitsh

Copy link
Copy Markdown
Author

@RollingVersions bump

pug-walk

security

pug-code-gen

security

pug-linker

security

pug-filters

security

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant