Background
CVE-2026-5760 (CVSS 9.8) showed that an LLM serving framework which renders a model-supplied chat_template through an unsandboxed template engine can be driven to remote code execution: a malicious model embeds a Server-Side Template Injection (SSTI) payload in tokenizer.chat_template, and when the template is rendered the payload reaches interpreter internals (e.g. Python's __class__ → __subclasses__ → os.system).
mlxcel renders model-supplied chat templates in src/server/chat_template.rs via minijinja. By construction this is not vulnerable to that RCE class:
minijinja::Value is a sealed type system with no reflection attributes (__class__ / __mro__ / __subclasses__ / __globals__), so there is no gadget chain from a string to an arbitrary callable.
configure_environment() (src/server/chat_template.rs:586) registers only pure helpers (raise_exception, strftime_now with its format argument ignored, and a set_unknown_method_callback at line ~616 that implements pure string/dict methods). None perform process, filesystem, or network I/O.
- No template loader is configured (no
{% include %} file disclosure), and pycompat / minijinja-contrib are not enabled.
- Clients cannot supply template source over HTTP — only model files and the operator
--chat-template flag can.
This issue does NOT report a vulnerability. It adds regression tests so this safe posture is enforced going forward and a future change (e.g. enabling pycompat, adding a file loader, or registering an I/O-capable function) cannot silently reintroduce the risk.
Tasks
Acceptance criteria
- New tests pass and run as part of the default
cargo test (not #[ignore]d).
- A deliberately-introduced regression — e.g. registering a dangerous function in
configure_environment — makes at least one new test fail.
- No runtime behavior change; tests only.
References
- CVE-2026-5760 / CERT VU#915947 (SGLang chat-template SSTI → RCE)
src/server/chat_template.rs — configure_environment (~line 586), set_unknown_method_callback (~line 616), apply / apply_raw_with_kwargs (~line 347), from_model_path (~line 64)
Companion hardening issue: #129
Background
CVE-2026-5760 (CVSS 9.8) showed that an LLM serving framework which renders a model-supplied
chat_templatethrough an unsandboxed template engine can be driven to remote code execution: a malicious model embeds a Server-Side Template Injection (SSTI) payload intokenizer.chat_template, and when the template is rendered the payload reaches interpreter internals (e.g. Python's__class__→__subclasses__→os.system).mlxcel renders model-supplied chat templates in
src/server/chat_template.rsviaminijinja. By construction this is not vulnerable to that RCE class:minijinja::Valueis a sealed type system with no reflection attributes (__class__/__mro__/__subclasses__/__globals__), so there is no gadget chain from a string to an arbitrary callable.configure_environment()(src/server/chat_template.rs:586) registers only pure helpers (raise_exception,strftime_nowwith its format argument ignored, and aset_unknown_method_callbackat line ~616 that implements pure string/dict methods). None perform process, filesystem, or network I/O.{% include %}file disclosure), andpycompat/minijinja-contribare not enabled.--chat-templateflag can.This issue does NOT report a vulnerability. It adds regression tests so this safe posture is enforced going forward and a future change (e.g. enabling
pycompat, adding a file loader, or registering an I/O-capable function) cannot silently reintroduce the risk.Tasks
#[cfg(test)]module ofsrc/server/chat_template.rs) that render representative Jinja2 SSTI gadget payloads throughChatTemplateProcessorand assert each produces either a render error or inert literal output — never a side effect. Cover at least:{{ ''.__class__ }},{{ ().__class__.__bases__ }},{{ ''.__class__.__mro__[1].__subclasses__() }},{{ self.__init__.__globals__ }}.{{ config }},{{ lipsum }},{{ get_flashed_messages() }},{{ cycler.__init__.__globals__ }}.content(and achat_template_kwargsvalue) of{{ 7 * 7 }}/{{ ''.__class__ }}must appear verbatim in the output, proving request-controlled data is never evaluated as template source.configure_environmentever registers a function/global outside an explicit allowlist, or if a template loader is ever set — so future additions are caught at test time.models/directory (i.e. not the#[ignore]dtest_all_local_model_templates_render).Acceptance criteria
cargo test(not#[ignore]d).configure_environment— makes at least one new test fail.References
src/server/chat_template.rs—configure_environment(~line 586),set_unknown_method_callback(~line 616),apply/apply_raw_with_kwargs(~line 347),from_model_path(~line 64)Companion hardening issue: #129