Two authenticated server-side template injection flaws in RAGFlow, both now on CISA's Known Exploited Vulnerabilities catalog, both stemming from the same root cause: unsandboxed Jinja2 rendering of user-supplied input. Here's exactly how they work, what happens after exploitation, and how to actually fix it.
Worth being precise about this before anything else, since coverage of this story varies in how carefully it's worded. CISA added CVE-2026-45312 and CVE-2026-28797 to its Known Exploited Vulnerabilities catalog — a designation that requires evidence of real-world exploitation, alongside a related cluster (CVE-2026-24770, a MinerU parser path-traversal flaw; CVE-2025-68700, a Canvas CodeExec sandbox-bypass issue; CVE-2025-69286, an account-access weakness). Federal agencies have until September 5, 2026 to patch.
Microsoft's own security research is more carefully worded than some of the coverage summarizing it: these specific CVEs are described as providing plausible technical context for an intrusion Microsoft investigated — not as the confirmed, attributed root cause of that specific incident. Both things are true simultaneously: active, real-world exploitation of this vulnerability class is confirmed by CISA's own listing criteria, while attribution of any one particular intrusion to these exact CVEs deserves the same caution Microsoft itself applied.
Location: rag/prompts/generator.py — the core component responsible for dynamically assembling retrieved database context with user prompts before sending them to the LLM.
Root cause: RAGFlow versions 0.24.0 and earlier pass user-supplied parameters into Python's Jinja2 templating library without sanitizing or restricting them first. Jinja2 is designed to render templates safely when the template source is trusted — it was never designed to safely render templates built from untrusted, attacker-controlled input.
Attack path: A regular, low-privileged user — including one who simply self-registered on a public-facing instance — builds a custom "Canvas" workflow combining an external data component (such as a web search node) with an LLM node, then injects malicious template syntax into that workflow. When RAGFlow renders the prompt, the injected template code executes on the host, not just inside the model's context window.
Location: RAGFlow's Agent workflow interfaces — specifically the Text Processing (StringTransform) and Message components.
Root cause: These components call Python's standard jinja2.Template() class directly, with no SandboxedEnvironment wrapping it. The distinction matters technically: Jinja2 ships with a genuinely secure sandboxed rendering mode built specifically for untrusted templates — these components simply don't use it.
Attack path: An attacker exploits Jinja2's native Python object introspection — submitting strings that reference base Python object attributes like __class__, __mro__, or __subclasses__ to walk the live Python object graph at runtime. This lets the attacker reach dangerous built-ins such as os.system() or subprocess.Popen() entirely from within what looks like ordinary template text, bypassing the application's intended logic completely and taking direct control of the underlying container.
SSTI-to-RCE is a well-understood vulnerability class on its own. What makes this pair specifically dangerous is what an attacker finds once they have command execution inside an AI orchestration container — a target-rich environment in a way a typical web application container isn't.
AI orchestration tools like RAGFlow inherently require broad cloud provider access — API keys for OpenAI, Anthropic, and cloud infrastructure providers — simply to function. These credentials are commonly stored as plaintext environment variables, which an attacker with command execution can read directly, often via a single command targeting /proc/1/environ. Where a compromised web server might yield a database password, a compromised AI orchestration layer can yield master credentials for every connected LLM provider at once.
Once an attacker recovers a connection string — a DATABASE_URL or equivalent — from the harvested environment variables, they can connect directly to the organization's PostgreSQL instance or vector database using fully legitimate credentials. From the database's perspective, this looks like an authorized connection, not an intrusion.
Beyond raw data, an attacker with this level of access can extract workflow schemas, corporate training logs, and private user conversation metadata — the operational fingerprint of how the organization's AI systems actually work, which is itself valuable reconnaissance for further attacks.
A generic SSTI vulnerability in a conventional web application is serious on its own. This particular case is worth understanding as its own category because of what a RAG engine's architecture inherently connects together: internal databases, vector stores, multiple LLM provider credentials, and orchestration logic, often in the same container. Microsoft's own framing of this campaign is worth taking seriously as general guidance, not just commentary on this one incident: defenders should monitor AI workloads according to their role in the control plane, not merely as isolated applications sitting alongside everything else.
jinja2.Template(), or any equivalent templating engine, on data that ultimately originates from user input, verify a sandboxed rendering mode is actually in use — not assumed.Nothing about the underlying vulnerability class here is new — server-side template injection has been a known, well-documented risk for web applications for years. What's genuinely new is the blast radius once it lands inside an AI orchestration layer specifically. A conventional web application compromised this way typically yields access to that application's own data. An AI orchestration layer compromised this way can yield master credentials for every connected LLM provider, direct database access, and the operational metadata of how an organization's entire AI stack actually works — all from a single entry point that, on paper, only required a low-privileged, self-registered account.