# Handlebars template injection and RCE in a Shopify app

Handlebars SSTI in Shopify Return Magic email templates allowed constructor access, escalating to RCE via Object.prototype.toString overwrite and bind.

- Payout: unconfirmed
- Severity: critical
- Program: Shopify
- Credited: Mahmoud Gamal
- Disclosed: 2019-04-04
- Write-up quality: 9/10
- Original: https://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html
- Library page: https://bugbountylibrary.com/r/blog%3Amahmoudsec-blogspot-com-2019-04-handlebars-template-injection-and-rce-html
- Tags: domain:web3 impact:rce kind:bounty platform:blog sev:critical tech:nodejs technique:chained technique:source-review vuln:rce vuln:ssti

**Target:** Email WorkFlow template engine (Handlebars) in Node.js app
**Root cause:** Handlebars allowed template access to object constructors (this.constructor.constructor) and invoked functions with the template scope as last argument, enabling Function constructor abuse; Object.prototype.toString could be overwritten to inject code.
**Steps:**
1. Inject `{{this}} {{self}}` into email template; observe `[object Object]` in received email confirming template evaluation
2. Identify engine as Handlebars by locally parsing `{{this}}` (returns `[object Object]`) vs mustache (returns nothing)
3. Access `{{this.constructor.constructor}}` to reach Function constructor
4. Note compiler appends template scope as last arg, breaking direct Function calls
5. Overwrite `Object.prototype.toString` via `defineProperty` to a bound function returning payload string
6. Use `bind()` to create function returning RCE payload, then set as toString
7. Trigger via `#blockHelperMissing` (avoids `#with` isFunction check) to call Function constructor with payload as body
8. Simpler PoC: `{{#with (string.sub.apply 0 codelist)}}` shifting context to Function constructor then apply
**How found:** Noticed `[object Object]` from `{{this}}` in test email, ruled out mustache by local testing, matched behavior to Handlebars, then read runtime.js and helper source to understand function invocation and context passing.
**Exploitation:** Attacker (shop owner) edits email workflow template with malicious Handlebars payload; on email send, template compiles and executes arbitrary JS in Node.js context, achieving RCE on Return Magic server.
**Escalation:** Chained SSTI detection to sandbox escape via constructor access and prototype manipulation, yielding full RCE.
**Insight:** When a template engine returns `[object Object]` for `{{this}}`, test constructor access; if functions are callable, inspect how the compiler passes context as trailing args and look for prototype methods like toString/bind to smuggle payloads past argument mangling.
