# Langflow: Unauthenticated RCE in Shareable Playgrounds

Langflow's public flow build endpoint accepts attacker-supplied Python in node template code, giving unauthenticated RCE on any deployment with a shared playground.

- Payout: Research
- Severity: critical
- Program: Langflow
- Found by: vbCrLf, andifilhohub, AntonioABLima
- Disclosed: 2026-06-16
- CVE: CVE-2026-48519
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-v5ff-9q35-q26f
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-v5ff-9q35-q26f
- Tags: area:ai domain:ai domain:web impact:rce kind:research platform:ghsa sev:critical tech:python technique:source-review vuln:rce

**Target:** /api/v1/build_public_tmp public flow build endpoint
**Root cause:** The public flow execution route rebuilds the graph from the client-supplied JSON payload and instantiates custom components from data.nodes[X].data.node.template.code.value without validating that the code matches the stored flow, so arbitrary Python is compiled and executed.
**Steps:**
1. Create a flow with a Chat Input node and enable Shareable Playground
2. Open the public link, execute the flow, and capture the `/api/v1/build_public_tmp/<flow-id>/flow?start_component_id=ChatInput-syEJp&log_builds=false&event_delivery=streaming` request as cURL
3. Replace `data.nodes[X].data.node.template.code.value` in the JSON body with arbitrary Python (e.g. `touch /tmp/pwned`)
4. Replay: `curl 'http://localhost:7860/api/v1/build_public_tmp/<flow-id>/flow?...' -H 'Content-Type: application/json' -b 'client_id=anything' --data-raw "$(cat test_with_python.json)"`
**How found:** Noticed the public build route reconstructs the graph from the request payload rather than the stored flow, then traced Graph.from_payload through instantiate_component to instantiate_class compiling the client-supplied code string.
**Exploitation:** Unauthenticated attacker only needs a public flow ID from a shared playground link; the POST body's node template code field is compiled via instantiate_class and executed server-side during graph build, yielding code execution as the Langflow process.
**Insight:** When a 'run public flow' endpoint accepts the full graph JSON, diff it against the stored flow: any field the server re-instantiates from the request (custom component code, class names) is a code-execution sink even behind an unauthenticated route.

## Proof of concept (copied exactly from the original report)

**cURL PoC hitting build_public_tmp with injected code**

```
curl 'http://localhost:7860/api/v1/build_public_tmp/<flow-id>/flow?start_component_id=ChatInput-syEJp&log_builds=false&event_delivery=streaming' \
  -H 'Content-Type: application/json' \
  -b 'client_id=anything' \
  --data-raw "$(cat test_with_python.json)"
Search for `touch /tmp/pwned` in the `test_with_python.json` and edit for any other code.
```

