critical · 10Jul 24, 2026

@prompty/core Server-Side Template Injection to Remote Code Execution

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

The @prompty/core TypeScript runtime rendered untrusted .prompty template files through an unsandboxed Nunjucks engine, letting an attacker traverse JavaScript prototype chains to execute arbitrary…

Package@prompty/core
Ecosystemnpm
Affected<= 0.1.4
Fixed in0.1.5
@prompty/core Server-Side Template Injection to Remote Code Execution

The problem

The @prompty/core package (npm, versions <= 0.1.4 and <= 2.0.0-beta.4) passed attacker-controlled .prompty template bodies directly to Nunjucks' renderString without any input sanitization.

Nunjucks does not sandbox execution and allows unrestricted JavaScript member access from templates. An attacker who could supply a malicious .prompty file, whether via a community repository, an LLM-generated file, or a cloned project, could traverse the constructor and prototype chain to reach Node.js globals and run arbitrary commands with the privileges of the host process.

Proof of concept

A working proof-of-concept for this issue in @prompty/core, with the exact payload below.

text
---
name: pwn
model:
  id: gpt-4o-mini
  provider: openai
template:
  format: jinja2
---
{{ ''.__proto__.constructor.constructor('return process')().mainModule.require('child_process').execSync('id').toString() }}

Nunjucks resolves dotted member access by walking JavaScript object properties with no allow-list. The payload climbs from an empty string literal up through __proto__ to its constructor (String), then to String's constructor (Function), calls it to get a reference to the global process object, and from there reaches require('child_process') to execute a shell command.

The fix in PR #404 (commit 047756f) adds a sanitization pass over all render inputs before they reach Nunjucks. It strips values down to own, enumerable data properties only and throws on any attempt to access constructor, prototype, or __proto__ keys, cutting off the traversal before it starts.

Template function calls are also disallowed entirely. Ordinary interpolation, loops, and conditionals over plain data continue to work.

Root cause: CWE-94 (Code Injection) and CWE-1336 (Improper Neutralization of Special Elements Used in a Template Engine). CVSS 10.0 critical.

The fix

Upgrade @prompty/core to 0.1.5 (stable) or 2.0.0-beta.5 (beta) or later. The patched renderer sanitizes all render inputs to own-data-only values and blocks constructor/prototype traversal and template function calls before passing anything to Nunjucks. No configuration change is required beyond the version bump.

Reporter not attributed.

References: [1][2][3][4]

Related research