handlebars-lang / handlebars-lang/handlebars.js

[Security] Proto-access control bypass via Map Symbol.toStringTag spoofing + HTML escape bypass

Open
#2,146 3 comments 0 reactions 1 assignee Claimed by @jaylinski View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.