Skip to content

fix: sandbox ImageRAGPrompt template rendering (SSTI, sibling of CVE-2026-2969) - #144

Open
joysinleung wants to merge 1 commit into
datapizza-labs:mainfrom
joysinleung:fix/image-rag-prompt-ssti-sandbox
Open

fix: sandbox ImageRAGPrompt template rendering (SSTI, sibling of CVE-2026-2969)#144
joysinleung wants to merge 1 commit into
datapizza-labs:mainfrom
joysinleung:fix/image-rag-prompt-ssti-sandbox

Conversation

@joysinleung

Copy link
Copy Markdown

Summary

ImageRAGPrompt in datapizza/modules/prompt/image_rag.py compiles user-supplied
template strings with a bare, unsandboxed jinja2.Template and renders them later.
This is the exact sibling pattern of ChatPromptTemplate (CVE-2026-2969 /
GHSA-q5xx-fxv3-xxqf), which was fixed by switching to jinja2.sandbox.SandboxedEnvironment
— but the fix was never applied to image_rag.py.

Change

Mirror the existing prompt.py fix (the CVE-2026-2969 remediation):

-from jinja2 import Template
+from jinja2.sandbox import SandboxedEnvironment
@@
-        self.user_prompt_template = Template(user_prompt_template)
+        env = SandboxedEnvironment()
+        self.user_prompt_template = env.from_string(user_prompt_template)
         self.image_prompt_presentation = image_prompt_presentation
-        self.each_image_template = Template(each_image_template)
+        self.each_image_template = env.from_string(each_image_template)

Why it's safe

  • Legitimate template-variable substitution ({{ var }}) still works — SandboxedEnvironment
    evaluates ordinary expressions.
  • Attribute-traversal escalation (''.__class__.__mro__[1].__subclasses__()) is blocked with
    SecurityError, neutralizing the SSTI → RCE path.
  • Matches the pattern already shipped and accepted in prompt.py.

Impact

CWE-1336 Server-Side Template Injection. Attacker-influenced template strings (prompt builder,
config/API field, multi-tenant template store) → arbitrary Python code execution in the host
process. Proposed CVSS 3.1: AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H = 7.2 High.

Testing

Defensive verification (no weaponized payload):

sandboxed render: 'RESULT=49'                                          # legit {{7*7}} still works
blocked as expected: SecurityError access to attribute '__class__' ... # gadget blocked

Full disclosure in #143.

ImageRAGPrompt compiled user-supplied template strings with a bare,
unsandboxed jinja2.Template, which allows server-side template injection
(CWE-1336) — the exact sibling pattern of CVE-2026-2969 / GHSA-q5xx-fxv3-xxqf,
which was fixed in prompt.py by switching to SandboxedEnvironment but was
never applied to image_rag.py.

Align with the existing fix: use jinja2.sandbox.SandboxedEnvironment +
env.from_string() for both template sinks (L27 user_prompt_template,
L29 each_image_template). Verified defensively: expression evaluation still
works for legitimate templates, while attribute-traversal gadgets
(().__class__.__mro__[1].__subclasses__()) raise SecurityError.

Related: datapizza-labs#143
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant