CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

GHSA-7gfh-x38p-prh3: Velocity.js: Remote Code Execution via property-read to Function constructor (bypass of GHSA-j658-c2gf-x6pq fix)

criticalCVSS 9.8
Summary Remote Code Execution (RCE) in velocityjs v2.1.6 via property-read to the Function constructor. This bypasses the fix for GHSA-j658-c2gf-x6pq ("Prototype Pollution in #set path assignment") — that advisory blocked constructor/proto/prototype only in the #set assignment handler (set.cjs), but property read expressions are unfiltered. Any application rendering attacker-controlled Velocity templates is vulnerable to arbitrary code execution on the server. Details GHSA-j658-c2gf-x6pq added isBlockedPathKey() to dist/cjs/compile/set.cjs:35-43, which blocks proto, constructor, and prototype keys. However, this check only runs when the #set directive assigns a value — it validates the assignment target path, not the value expression being evaluated. The value expression is evaluated via getReferences() in dist/cjs/compile/references.cjs:16, which calls getAttributes() at line 81. The property access at line 88-89 has no filtering: // references.cjs:81-91 getAttributes(property, baseRef, ast) { if (property.type === "property") { return baseRef[property.id]; // ← NO BLOCK on "constructor", "prototype", etc. } ... } Meanwhile, set.cjs:35-43 properly blocks these keys, but only for the #set target: // set.cjs:35-43 isBlockedPathKey(baseRef, key, isEnd) { if (key === PROTO_KEY) return true; // "proto" if (key === "prototype" && typeof baseRef === "function") return true; return !isEnd && PROTOTYPE_CHAIN_KEYS.has(key) && !hasOwnProperty(baseRef, key); } The exploit chain: 1. $x.constructor → getAttributes() → {}["constructor"] → Object 2. .constructor → getAttributes() → Object["constructor"] → Function 3. ("return process.mainModule.require('child_process').execSync('whoami')") → calls Function(...) → creates a function 4. The #set assigns the result to $f, which is then rendered as $r The #set handler validates $f as the assignment target (which passes — f is not blocked), but never inspects the right-hand expression for prototype chain traversal. PoC const veloc

Details

Source
GitHub Security Advisories (INTL · database · site)
Severity
critical — CVSS 9.8
Published
2026-07-24
Last updated
2026-07-24
Exploitation
Not in CISA KEV at last sync

Original advisory: https://github.com/advisories/GHSA-7gfh-x38p-prh3

More from GitHub Security Advisories