Security News

Why a CPython Bug Lets Attackers Escape AI Inference Sandboxes

A CPython sandbox escape lets a backdoored AI chat template run code inside vLLM and similar engines. RunSybil's fix has not reached Python 3.12.

Brandefense logo 6 Min Read
Dark glass index card with a thin red neon circuit trace growing from its surface, cover art for: a formatting template that turns into a running program

A CPython sandbox escape lets an attacker hide working code inside an AI model’s own chat template. RunSybil, a security research firm, found a memory-safety bug in CPython that an attacker can trigger through Jinja template rendering.

Template rendering is the step that turns a model’s raw prompt format into text an inference engine can run. RunSybil demonstrated the flaw against vLLM, an open-source inference engine, and says a fix has not reached every supported version of Python.

Security teams that have reviewed only the model file’s weights, and not its template files, have reviewed half the package. The same chat_template.jinja file ships inside the same repository download as the weights themselves.

Why Are Chat Templates a New Kind of Attack Surface?

Inference engines treat a chat template as configuration, not as code that needs review. Hugging Face and other model hosts let any model publisher ship its own chat_template.jinja file alongside the model weights, and most serving stacks render it automatically.

Jinja is a template language, built to format text, not to run arbitrary Python. RunSybil’s finding matters because it turns that formatting step into a path to the interpreter underneath it, through a bug in CPython rather than in Jinja’s own template logic.

How Does the CPython Sandbox Escape Work?

CPython caches a generic type alias’s parameters the first time it needs them, such as the parameters of dict[K, V]. The bug sits in _Py_subs_parameters, the function that substitutes a new value into those cached parameters.

If a parameter gains the ability to be substituted after CPython has already cached the parameter list, a lookup for that parameter returns -1 instead of its real position. In a release build, the code uses that -1 as an array index anyway and reads whatever sits there, which can be the cached hash of an unrelated tuple.

A debug build of CPython catches this with an assertion and stops. RunSybil’s write-up says a release build does not, so the bad read continues and hands the attacker a pointer to a real Python object instead of the number it expected.

RunSybil built a working example around this gap. The firm says it created a version of the small open model Qwen2.5-0.5B-Instruct with a backdoored chat_template.jinja file. It then used the bad pointer to recover real Python objects, such as strings, types and code objects.

With real Python objects in hand, the firm says it could build a working code object and run it. RunSybil frames the result plainly: code hidden inside a chat template can run inside the process that serves the model, with that process’s own privileges.

How the CPython Sandbox Escape Runs
How the CPython Sandbox Escape RunsAttack path in 5 steps: 1, Backdoored chat_template.jinja (Model Supply Chain), then uploaded to a model repository; 2, Template rendered at load time (Serving Process), then the inference engine renders it, per RunSybil; 3, Generic alias substitution (CPython Interpreter), then a cached parameter lookup returns -1; 4, Arbitrary Python object recovered (CPython Interpreter), then the bad read returns a real object, not a number; 5, Code executes in the process (Serving Process).Model Supply ChainServing ProcessCPython Interpreteruploaded to a model…the inference engine…a cached parameter lookup…the bad read returns a…Backdooredchat_template.jinjaTemplate rendered atload timeGeneric aliassubstitutionArbitrary Pythonobject recoveredCode executes in theprocess
  1. Backdoored chat_template.jinjaModel Supply Chainuploaded to a model repository
  2. Template rendered at load timeServing Processthe inference engine renders it, per RunSybil
  3. Generic alias substitutionCPython Interpretera cached parameter lookup returns -1
  4. Arbitrary Python object recoveredCPython Interpreterthe bad read returns a real object, not a number
  5. Code executes in the processServing Process

Who Is Exposed: vLLM, Bedrock and Other Inference Engines

RunSybil says it demonstrated the issue against vLLM, and that AWS Bedrock applied an expedited mitigation after the firm’s disclosure. DigitalOcean’s bring-your-own-model service is also named as exposed in the write-up.

RunSybil says Jinja, the template project, pointed to CPython rather than treat the gap as its own issue. Hugging Face did not reply during the firm’s 90-day disclosure window, per RunSybil’s account, and vLLM has acknowledged the report but has not committed to a fix of its own.

RunSybil frames the risk as a supply-chain problem more than a single-engine bug. A chat template travels with the model file itself, so any downstream platform that pulls a model from a public hub inherits whatever that template does when it gets rendered.

The pattern is not specific to one engine. Any system that renders a Jinja chat template pulled from a model repository, and runs on an exposed CPython version, takes on the same risk, per RunSybil’s account.

Why Hasn’t CPython Fixed This for Every Version?

The fix itself is public. CPython merged pull request 155761 into its main branch on 14 August 2026. The project describes the change as a check that catches a missing parameter instead of reading past the end of a cached tuple.

We checked the CPython project’s own repository directly. The same fix reached the 3.15 branch the same day, and the 3.14 and 3.13 branches on 8 September 2026. The 3.12 branch has not received the same change.

Python’s own release page lists 3.12 as a security branch, which only takes fixes the project classifies as security issues. RunSybil’s write-up says CPython’s maintainers do not classify this as a vulnerability, because sandboxing untrusted code was never a supported use of the interpreter. That is why an ordinary bug fix does not reach a branch that only takes security fixes.

Python’s own schedule keeps 3.12 in that security-only phase until October 2028. Teams who stay on 3.12 for AI workloads should not expect this fix to arrive through a routine update.

What Should AI Teams Do Now?

RunSybil’s own advice is direct: treat a “security fix only” build of CPython as unsafe for any workload that runs sandboxed code, template engines or expression evaluators. It tells teams to assume an attacker can reach code execution through them.

We recommend three checks. First, find every place a chat template, system prompt file or similar text asset is pulled from a model repository and rendered before a request runs. Second, check whether that rendering step runs on CPython 3.12 or an earlier security-only branch. Third, treat any model file from outside your own pipeline, including its chat template, as untrusted input until it passes review.

On detection, we recommend scanning any chat template file pulled from an external model repository for logic beyond simple text substitution. Watch for code that reads or sets object attributes before the template reaches a production serving stack.

This is not the first sandbox boundary an AI platform has leaned on and lost. Our coverage of Beta9’s own tenant sandbox escape describes the same pattern in a different compute layer. Brandefense’s top threats to AI agents page and our sandbox glossary entry cover the wider concept this flaw sits inside.

Frequently Asked Questions.

What is the CPython sandbox escape that RunSybil found?

It is a memory-safety bug in how CPython substitutes parameters into a cached generic type alias. RunSybil says an attacker can trigger it through a backdoored Jinja chat template to run arbitrary code.

Does the fix cover Python 3.12?

Not yet. CPython's own repository shows the fix reached the 3.15, 3.14 and 3.13 branches, but 3.12 stays on the security-only branch that only receives fixes CPython classifies as security issues.

Which AI inference engines does RunSybil name?

RunSybil demonstrated the issue against vLLM and names AWS Bedrock and DigitalOcean's bring-your-own-model service as having applied their own mitigations.

Has CPython published a security advisory for this issue?

CPython's own list of GitHub security advisories for the project carries none for this issue, as of 6 November 2026. That matches RunSybil's account that the maintainers did not classify it as a vulnerability.

Sources

  1. 1 CPython 0-Day Vulnerabilities Threaten the AI Supply Chain, RunSybil Research
  2. 2 CPython Developer Guide: Status of Python Versions
Share