Critical · CVSS 9.9 May 29, 2026 · Yuu / Verichains (RAGFlow)

RAGFlow Prompt Generator Server-Side Template Injection Leads to Remote Code Execution

Unsandboxed Jinja2 Environment in citation_prompt() lets any authenticated user pop a shell via a DuckDuckGo→LLM Canvas workflow

RAGFlow, an open-source Retrieval-Augmented Generation engine from infiniflow, contains a critical server-side template injection in versions 0.24.0 and earlier. The prompt generator (rag/prompts/generator.py) renders user-supplied citation guidelines through an unsandboxed Jinja2 environment. Any authenticated user — including a self-registered, low-privilege account — can build a Canvas workflow chaining a DuckDuckGo tool into an LLM component, embed a Jinja2 payload in the prompt, and execute arbitrary OS commands on the RAGFlow server with the service's own privileges. Fixed in v0.25.0 by switching to jinja2.sandbox.SandboxedEnvironment.

1 CVE
9.9 CVSS Score
SSTI → RCE Vulnerability Class
Post-Auth Access Required

Technical Breakdown

CVE-2026-45312 CRITICAL · CVSS 9.9 Post-Auth SSTI → RCE

RAGFlow Prompt Generator Server-Side Template Injection Leads to Remote Code Execution

rag/prompts/generator.py instantiates a module-level PROMPT_JINJA_ENV = jinja2.Environment(autoescape=False, trim_blocks=True, lstrip_blocks=True) — the plain, unsandboxed Jinja2 environment that exposes full Python object introspection via __globals__/__builtins__. Its citation_prompt() function renders attacker-controlled text pulled from <CITATION_GUIDELINES> tags inside an LLM component's sys_prompt — set via the Canvas DSL — directly through that environment as a template rather than as inert string data, so Jinja2 control syntax executes server-side instead of being displayed.

CWE: CWE-1336 — Improper Neutralization of Special Elements Used in a Template Engine  |  Fixed in: v0.25.0  |  Workaround: disable open self-registration / restrict Canvas creation to trusted users

Root Cause

rag/prompts/generator.py builds a module-level PROMPT_JINJA_ENV = jinja2.Environment(autoescape=False, trim_blocks=True, lstrip_blocks=True) — the plain, unsandboxed Jinja2 environment that exposes full Python object introspection (__globals__, __builtins__, etc.). Its citation_prompt() function renders user-controlled text — specifically content pulled from <CITATION_GUIDELINES> tags inside an LLM component's sys_prompt, set via the Canvas DSL — directly through that environment as a template rather than as inert string data, so attacker-supplied Jinja2 syntax executes server-side instead of being displayed.

Vulnerable Pattern

Any time a string that originated from user input reaches a template engine's .from_string()/.render() path instead of a plain string-formatting call, the engine's full expression language — attribute access, method calls, object graph traversal — becomes available to the attacker. Jinja2's default Environment has no barrier between a rendered template and Python's object model; only jinja2.sandbox.SandboxedEnvironment restricts attribute/method access. RAGFlow used the former for a field that was never meant to hold template syntax.

Why AI Services Are High-Value

RAG platforms are deliberately configured to hold an organization's most sensitive internal knowledge — contracts, source code, credentials-adjacent documentation — indexed for retrieval. The same container also holds live LLM provider API keys and vector-store credentials needed to serve queries. An RCE here doesn't just compromise a web app; it compromises the knowledge base and the keys protecting it in a single step, with the added twist that the attack surface (a "prompt" field) looks like ordinary product functionality rather than an obvious injection point.

The Fix

v0.25.0 replaces the unsandboxed environment with jinja2.sandbox.SandboxedEnvironment, which blocks access to dunder attributes and unsafe built-ins during rendering. No workaround was published by the vendor pre-patch; the closest mitigation is preventing untrusted accounts from reaching the vulnerable code path at all — disable open self-registration or restrict who can create/execute Canvas workflows until you upgrade.

Attack Chain

1

Recon / account acquisition

Attacker discovers a reachable RAGFlow instance (default self-registration enabled) and creates a normal user account; no special role or admin access needed.

Defensive note: disable open self-registration or gate it behind invite/SSO; alert on new-account-to-first-Canvas-execution intervals under a few minutes.

2

Malicious model registration

Attacker registers a fake OpenAI-compatible LLM model pointing at an attacker-controlled endpoint (not strictly required if using an existing configured model, but commonly used to control response/timing).

Defensive note: audit/restrict who can add custom model providers; log outbound model-provider URL configuration changes.

3

Canvas construction with payload

Attacker builds a Canvas workflow chaining a DuckDuckGo search tool into an LLM component, and embeds a Jinja2 SSTI payload (e.g. {% set g = cycler.__init__.__globals__ %}...os.popen(...)) inside <CITATION_GUIDELINES> tags in the LLM component's sys_prompt.

Defensive note: monitor Canvas DSL payloads/API calls for Jinja2 control syntax ({%, {{, __globals__, __builtins__) in prompt/system-prompt fields — a strong, low-false-positive signal since normal users never legitimately type template syntax there.

4

Trigger / server-side render

Attacker executes the Canvas; the DuckDuckGo component populates retrieved chunks, which flows into citation generation, causing citation_prompt() to render the attacker's string through the unsandboxed PROMPT_JINJA_ENV.from_string()/render path.

Defensive note: runtime egress/process monitoring on the RAGFlow app container — unexpected child processes (os.popen, subprocess) spawned from the Python web-worker process are the tell.

5

Command execution / impact

Arbitrary OS commands run with the privileges of the RAGFlow server process (container), giving the attacker code execution, filesystem access to mounted volumes (documents, vector-store credentials, LLM API keys), and a foothold for lateral movement into whatever network the RAGFlow container reaches.

Defensive note: least-privilege container user (non-root), network egress restrictions from the RAGFlow pod/container, and secrets stored outside the container filesystem (vault/KMS) so RCE doesn't equal instant credential theft.

Impact

RAG platforms sit at the intersection of an organization's most sensitive internal knowledge and its LLM infrastructure — a single template-injection RCE here compromises both the indexed documents and the credentials protecting them.

Remote Code Execution / Host Compromise

  • Arbitrary OS command execution as the RAGFlow service account inside the container
  • Full read/write of any files mounted into the container (uploaded documents, configs, .env)
  • Potential container escape or pivot if the container has excess capabilities or a mounted Docker socket
  • Persistence via cron/webshell drop if writable paths exist

Credential & Secret Theft

  • Access to LLM provider API keys (OpenAI-compatible endpoints, embedding providers) stored in RAGFlow config/DB
  • Access to vector database (Elasticsearch/Infinity) connection details present in the app's environment
  • MySQL/Redis connection strings typically present in the app's environment
  • Ability to read session/auth tokens of the RAGFlow application itself for further privilege escalation

Data Confidentiality & Integrity (RAG corpus)

  • Exfiltration of ingested/indexed documents — often sensitive internal knowledge bases by design of a RAG tool
  • Tampering with retrieved chunks/citations to poison downstream LLM answers (indirect prompt injection at scale)
  • Deletion or corruption of the knowledge base via filesystem/DB access gained post-RCE
  • Loss of integrity guarantees for any downstream system consuming RAGFlow's citations or generated answers

Defensive Tutorial

IMMEDIATE · 0–24 HRS

Patch to v0.25.0 or later

Immediate

Re-pull the infiniflow/ragflow image tagged v0.25.0+ and redeploy; confirm the fix by checking that rag/prompts/generator.py instantiates jinja2.sandbox.SandboxedEnvironment, not jinja2.Environment.

IMMEDIATE · 0–24 HRS

If you cannot patch immediately, disable self-registration

Immediate

Set whatever env/config flag controls open signup (RAGFlow's REGISTER_ENABLED/equivalent in docker/.env or admin settings) to prevent low-trust accounts from being created at all.

IMMEDIATE · 0–24 HRS

Grep logs for exploitation indicators

Immediate

Search application/API logs for Canvas save/execute requests containing template syntax: patterns like {{, {%, __globals__, __builtins__, __import__, cycler, specifically in CITATION_GUIDELINES payloads with embedded braces.

IMMEDIATE · 0–24 HRS

Rotate secrets reachable from the RAGFlow container

Immediate

Any LLM API keys, DB credentials, or vector-store tokens present in the RAGFlow environment/config should be rotated now if the instance was internet-reachable and self-registration was ever enabled pre-patch.

SHORT-TERM · 1–7 DAYS

Restrict Canvas creation/execution via RBAC

Important

If RAGFlow's role model allows it, limit who can build/run Canvas workflows (especially DuckDuckGo + LLM chains) to a trusted admin group rather than all authenticated users.

SHORT-TERM · 1–7 DAYS

Egress-restrict the RAGFlow container

Important

Apply a network policy (Kubernetes NetworkPolicy / Docker network rules) so the RAGFlow app pod cannot make arbitrary outbound connections.

SHORT-TERM · 1–7 DAYS

Run the RAGFlow service as non-root with a read-only root filesystem

Important

Where feasible, drop unnecessary Linux capabilities in the container spec in addition to the non-root/read-only posture.

LONG-TERM

Add template-injection detection to CI/SAST for internal forks

Important

Flag any jinja2.Environment(...) (non-sandboxed) instantiation that renders user-controlled strings; this exact pattern recurred twice in RAGFlow (this CVE and a separate StringTransform/Message-component SSTI, GHSA-vvwj-fvwh-4whx).

LONG-TERM

Track this component in your SBOM/vuln-management pipeline

Important

Pin infiniflow/ragflow >= 0.25.0 and subscribe to github.com/infiniflow/ragflow/security/advisories — this codebase has shown a pattern of unsandboxed-template issues across multiple components.

References

  • GitHub Security Advisory GHSA-wpg4-h5g2-jxm6 — vendor advisory with patch details and timeline.
  • NVD Entry CVE-2026-45312 — CVSS 9.9, CWE-1336, affected version range.
  • Vendor Fix infiniflow/ragflow PR #14068 — the SandboxedEnvironment fix, authored by Lyutoon.
  • CWE Reference CWE-1336 — Improper Neutralization of Special Elements Used in a Template Engine
Advisory analysis by Spectreworks AI. Original research by Yuu (ankuukino/anzuukino, VNUHCM-UIT/Verichains). All defensive recommendations are based on publicly available disclosure information. Verify patch applicability against your specific deployment before production changes.