handlebars-lang / handlebars-lang/handlebars.js
[Security] Proto-access control bypass via Map Symbol.toStringTag spoofing + HTML escape bypass
- Dominant language
- JavaScript
- Stars
- 18.7k
- Forks
- 2.1k
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
Three security findings in Handlebars.js v5.0.0-alpha.1:
### Finding 1: Proto-Access Control Bypass via Fake Map (Medium)
**File:** `lib/handlebars/runtime.js:119-122`
`lookupProperty` completely skips proto-access controls for Map objects. Map detection uses `Object.prototype.toString` which is spoofable via `Symbol.toStringTag`:
```js
const fakeMap = { [Symbol.toStringTag]: 'Map', get(key) { return key === 'constructor' ? Function : undefined; } };
// lookupProperty(fakeMap, 'constructor') returns Function, bypassing the blocklist
```
**Fix:** Use `instanceof Map` instead of toString tag check.
### Finding 2: HTML Escaping Bypass via toHTML Duck-Typing (Medium)
**File:** `lib/handlebars/utils.js:61-66`
`escapeExpression` treats any object with a `toHTML` property as SafeString (no `instanceof` check). Attacker-controlled data with `toHTML` bypasses HTML escaping in `{{}}` expressions.
**Fix:** Use `instanceof SafeString` check.
### Finding 3: AST Injection via Direct AST Input (Medium)
**File:** `lib/handlebars/compiler/compiler.js:476-485`
`compile()` accepts pre-parsed AST objects without structural validation, enabling code injection via crafted AST nodes through the `Function()` constructor.
**Fix:** Validate AST structure before compilation.
Contributor guide
Assessment
This issue has not been assessed yet.