Summary
mcpgateway/plugins/framework/loader/config.py:80 builds the Jinja env for rendering plugins/config.yaml with autoescape=True:
jinja_env = SandboxedEnvironment(loader=jinja2.BaseLoader(), autoescape=True)
rendered_template = jinja_env.from_string(template).render(env=os.environ)
autoescape=True HTML-encodes &, <, >, " in the rendered output. That's correct for HTML templates and wrong for YAML — any Jinja-rendered value (e.g. {{ env.REDIS_URL }} or any other env var passed through this path) containing those characters is silently corrupted before yaml.safe_load consumes it.
Concrete failure cases
REDIS_URL=redis://user:p&w@host:6379/0 (password containing &) renders as redis://user:p&w@host:6379/0 → broken URL.
- Any env-sourced TLS cert content, API key, or token containing
<, >, ", or & → silently corrupted.
- The corruption is silent: YAML parses successfully, plugin init fails downstream with a confusing error that doesn't point back at the encoding step.
Affects every Jinja-templated value in plugins/config.yaml, not just redis_url. Surfaced during review of #4582.
Proposed fix
jinja_env = SandboxedEnvironment(loader=jinja2.BaseLoader(), autoescape=False)
autoescape=False is the right default for non-HTML output; YAML's own escaping handles structural characters at the yaml.safe_load layer.
Acceptance criteria
Summary
mcpgateway/plugins/framework/loader/config.py:80builds the Jinja env for renderingplugins/config.yamlwithautoescape=True:autoescape=TrueHTML-encodes&,<,>,"in the rendered output. That's correct for HTML templates and wrong for YAML — any Jinja-rendered value (e.g.{{ env.REDIS_URL }}or any other env var passed through this path) containing those characters is silently corrupted beforeyaml.safe_loadconsumes it.Concrete failure cases
REDIS_URL=redis://user:p&w@host:6379/0(password containing&) renders asredis://user:p&w@host:6379/0→ broken URL.<,>,", or&→ silently corrupted.Affects every Jinja-templated value in
plugins/config.yaml, not justredis_url. Surfaced during review of #4582.Proposed fix
autoescape=Falseis the right default for non-HTML output; YAML's own escaping handles structural characters at theyaml.safe_loadlayer.Acceptance criteria
SandboxedEnvironmentconstructed withautoescape=False&,<,>,"round-trips through Jinja substitution unchanged