
On 3 November, security firm RunSybil showed that one file inside a model repository, chat_template.jinja, can run arbitrary code inside the vLLM process that serves the model. The cause is a CPython memory-safety bug, and the Python project says a Python sandbox is not a security boundary, so the fix has not reached every supported Python version.
AG Tech Consulting's advice for clients this week: treat every model you did not train yourself as executable code, not as data. Find out which Python minor version each of your inference images runs, put bring-your-own-model workloads in isolated, credential-free sandboxes, and review and pin chat templates the same way you review application code. This is the need of the hour, because the sandbox that renders those templates is no longer something you can assume will hold.
What RunSybil found
Every chat model ships a chat template: a small Jinja program that turns a list of messages into the token sequence the model expects. It travels with the model, as chat_template.jinja or inside tokenizer_config.json. Hugging Face Transformers renders it with Jinja's ImmutableSandboxedEnvironment, and vLLM's advisory GHSA-542m-9234-8gvf describes the same design: the template is compiled and rendered inside that sandbox.
The assumption is simple. If the sandbox holds, a third-party template is safe to render. RunSybil's blog post, written by Darius Houle and dated 3 November 2026, shows how quickly that assumption can collapse.
The team built a copy of Qwen/Qwen2.5-0.5B-Instruct with a backdoored chat_template.jinja. When they interacted with it through an inference engine like vLLM, arbitrary code ran in the serving process.
RunSybil then shared proof-of-concept exploits with many inference providers that support bring-your-own-model (BYOM) features. In its words, the outcome was "a very diverse set of responses and post-exploitation security postures."
How the escape works
The bug sits in CPython's typing code. According to RunSybil, a template can reach a memory-safety flaw in that code from inside the Jinja sandbox. The check that should have stopped it exists only in debug builds, so in a normal release build it is compiled out.

The mismatch. Python's own sandboxed environment was never designed to contain a bug in the interpreter itself. Once a template reaches such a bug, the sandbox rules no longer apply, and the template can run code with the privileges of the serving process. The CPython fix adds the missing check on the lookup result and raises TypeError instead.
Let us be clear about what this is not. It is not a prompt injection, and the model weights can be untouched. The payload sits in a text file that your serving stack renders before the first token is generated.
Who owns the fix?
This is where the story becomes a governance problem. RunSybil reports the positions of each party.
CPython says: "CPython does not support sandboxing untrusted Python code as a security boundary, so escapes from such a sandbox are not vulnerabilities in Python and should be reported to the sandbox's developers instead."
Jinja's maintainers replied: "Report this to cpython. It's problem with cpython, not with Jinja." The Jinja documentation itself says the sandbox "alone is not a solution for perfect security."
Hugging Face did not respond within the 90-day disclosure window, according to RunSybil.
vLLM acknowledged the report but, in RunSybil's words, "has not decided whether it will offer a mitigation."
Each position is defensible on its own. Together, they leave the bug class with no owner, and the AI supply chain depends on exactly that component.
A public fix does exist. Issue gh-155752 was opened on 13 August and PR #155761 was merged to main on 14 August. It adds a check on the lookup result and raises TypeError instead of indexing with -1. Backports to 3.15, 3.14 and 3.13 followed, and the changelogs list the fix in 3.15.0 rc2, 3.14.8 and 3.13.16.
The 3.12 and 3.11 changelogs do not list it. In the pull request, a maintainer removed the 3.10, 3.11 and 3.12 backport labels with the comment, "this seems like a regular bug to me", while another noted that crashes are usually backported "since they can be security vulnerabilities." RunSybil and an oss-security post of 5 November say upstream is not backporting the fix to security releases. The record is more nuanced: 3.13 is a security-only branch and did get it, but 3.12 and 3.11 did not.
Per the Python developer guide, 3.12 reaches end of life in October 2028 and 3.11 in October 2027. RunSybil points out that much of the AI ecosystem is still aligned on Python 3.12 and warns that organic adoption of the fixes may not come until late 2028.
Not the first template problem
Chat templates have been an attack surface before. CVE-2024-34359 in llama-cpp-python came from loading the chat template out of a .gguf file's metadata and passing it to a Jinja formatter; NVD scores it 9.6.
vLLM's own advisory, GHSA-542m-9234-8gvf (CVE-2026-115911, medium, published 28 October, fixed in 0.32.0), makes a quieter point. The sandbox "prevents code-execution escapes but imposes no wall-clock timeout, no output-size cap, and no nested-loop or binop limit." A malicious model repository loaded with trust_remote_code=False can wedge every chat endpoint for every tenant until the process restarts, and a string-multiplication variant can OOM-kill the API server.
The lesson is plain. trust_remote_code=False, which is the default in vLLM, stops a repository from shipping Python files. It does not make the repository safe, because the template is still code that you execute.
What worked, and what it tells us
RunSybil singles out two providers. DigitalOcean guarded its BYOM service with multi-tier isolation, and the attack was "fully contained", with no way found to move laterally in its infrastructure. AWS worked with RunSybil to implement a mitigation in AWS Bedrock.
Notice the difference. One provider assumed the sandbox could fail and built walls behind it. That design, and not the sandbox, is what protected the customers.
The future security risk: bugs found by AI faster than they are owned
RunSybil says human effort paired with GPT-5.6 Sol found this exploit in less than a day, and that memory-safety flaws in the CPython ecosystem "pose a growing risk as AI models get better at discovering them." It describes the post as part two of a series on sandbox escapes in the Python ecosystem. Four risks follow for CTOs and CISOs.
1. Ownerless bug classes. When the interpreter, the sandbox library, the model hub and the serving engine each point at another party, patches arrive late or only for newer Python versions.
2. Templates as a carrier. A template is a small, diff-friendly text file inside a multi-gigabyte repository. It is easy to miss in review, and it is copied along whenever a repository is cloned or mirrored.
3. Multi-tenant blast radius. One backdoored model in a shared serving process means one compromised process, and in a shared deployment that process handles every tenant's requests.
4. Slow runtime upgrades. RunSybil notes that major portions of the AI ecosystem are still aligned on Python 3.12, so a fix that exists upstream can take a very long time to reach production.
RunSybil's own advice applies to every component of this kind: treat the security guarantees as best-effort, and assume an attacker can reach arbitrary code execution through them.
Checklist for this week
Inventory every place you render a chat template that came from outside: vLLM, Transformers, llama.cpp bindings, gateways, notebooks and any BYOM service you offer or buy. Record the Python minor version of each inference image, and move to builds that list gh-155752 in their changelog (3.13.16, 3.14.8 or later, or 3.15). For images on Python 3.12 or 3.11, put a dated upgrade plan in the risk register, because those changelogs do not list the fix. Treat chat_template.jinja and tokenizer_config.json as code. Pin every model by commit hash, review template changes, and serve from an internal mirror instead of pulling from a public hub at deploy time. Run third-party models in single-tenant, least-privilege sandboxes: no cloud credentials, no metadata-service access, read-only filesystem, default-deny egress. Do not expose chat_template or chat_template_kwargs to API clients. Keep vLLM on 0.32.0 or later, keep --trust-remote-code off, and enable --enable-tokenizer-info-endpoint only if you need it. Put CPU, memory and time limits around template rendering, as the Jinja documentation advises, and alert when a render hangs. Ask every BYOM provider, in writing, how template rendering is isolated and what happens if the process is compromised. Monitor serving processes for unexpected child processes, new files in /tmp and outbound connections right after a model is loaded. Add a model-onboarding gate with an owner: provenance check, template review and an isolated test run before any model reaches production.
Bottom line
A chat template looks like formatting. In reality it is a program written by whoever published the model, run by your serving stack, inside a sandbox whose own maintainers say it is not a security boundary.
The point is simple. Patch what has a fix, isolate what does not, and do not let "it is only a template" be the sentence that ends your security review.
Sources
https://www.runsybil.com/blog/cpython-0-day-vulnerabilities-threaten-the-ai-supply-chain https://www.openwall.com/lists/oss-security/2026/11/05/11 https://github.com/python/cpython/issues/155752 https://github.com/python/cpython/pull/155761 https://github.com/python/cpython/pull/155772 https://docs.python.org/3.13/whatsnew/changelog.html https://devguide.python.org/versions/ https://jinja.palletsprojects.com/en/stable/sandbox/ https://github.com/huggingface/transformers/blob/main/src/transformers/utils/chat_template_utils.py https://github.com/vllm-project/vllm/security/advisories/GHSA-542m-9234-8gvf https://docs.vllm.ai/en/stable/usage/security/ https://docs.vllm.ai/en/stable/configuration/engine_args/ https://nvd.nist.gov/vuln/detail/CVE-2024-34359
Also on our website: https://agtechconsulting.ai/insights/model-chat-template-cpython-bug-code-execution.html
Want help inventorying where third-party models and templates enter your stack, isolating bring-your-own-model workloads, or planning the Python upgrade path for your inference images? Email avinash@agtechconsulting.ai, visit agtechconsulting.ai, or book a 30-minute call: https://calendly.com/avinash-dubey-30-min-catchup/meeting-with-ag-tech
Thanks to RunSybil, Darius Houle, the CPython and Pallets maintainers, vLLM, Hugging Face, DigitalOcean and Amazon Web Services for the work this builds on.
Originally published on LinkedIn in the Your CTO Advisor newsletter: read and comment on LinkedIn →


