Add vulnerability detection module for CVE-2026-33017 (Langflow unauthenticated RCE) - #1653
Add vulnerability detection module for CVE-2026-33017 (Langflow unauthenticated RCE)#1653NSK-394 wants to merge 9 commits into
Conversation
…henticated RCE)
- Detects the unauthenticated flow-data injection flaw in Langflow's
/api/v1/build_public_tmp/{flow_id}/flow endpoint (CVSS 9.8, CISA KEV)
- Chains 3 requests: unauthenticated token via auto_login, flow creation,
and malicious CustomComponent submission, then polls the job event
stream for a distinctively-named injected node
Detection scope: confirms the endpoint processes attacker-controlled flow
node data on vulnerable versions (<=1.8.2) versus discarding it on patched
versions (>=1.9.0), tested against both live containers. Does not
independently verify code execution -- the underlying exec() call could
not be confirmed to fire in testing, so the module is scoped as detecting
the input-validation flaw that is the CVE's root cause, not confirmed RCE.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Summary by CodeRabbit
WalkthroughAdded a Nettacker module for CVE-2026-33017. It retrieves a token, creates a public flow, submits a uniquely identified ChangesLangflow CVE-2026-33017 detection
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@nettacker/modules/vuln/langflow_cve_2026_33017.yaml`:
- Around line 55-68: Add a cleanup step after the event check to delete the
created flow using the captured flow_id, ensuring the temporary PUBLIC flow from
Step 2 is removed even after repeated scans. Reuse the module’s existing
authorization and request conventions, and place cleanup after all checks that
depend on flow_id.
- Around line 41-43: Update every affected URL entry in the Langflow CVE module
to use the established schema-and-ports fuzzer pattern from
langflow_cve_2025_3248.yaml instead of hardcoding http://{target}:7860. Apply
this consistently to the referenced auto-login and other endpoint definitions so
scans support HTTP/HTTPS and ports 80, 443, and 7860.
- Around line 45-53: Update the response conditions in the Langflow CVE check so
`save_to_temp_events_only` captures the actual token, `flow_id`, and `job_id`
values rather than matching only their field names. In the `content` regex
patterns, include the surrounding delimiters and empty capture groups around
each field’s body/value so the stored match list places the value at
`dependent_on_temp_event[*]['content'][0]`; preserve the existing status-code
condition.
- Around line 117-118: Update the build events configuration to use job_id for
the events endpoint path instead of flow_id, while leaving
dependent_on_temp_event unchanged.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 0d5b5598-350b-4b90-95af-86bbb787b7b3
📒 Files selected for processing (1)
nettacker/modules/vuln/langflow_cve_2026_33017.yaml
|
@codex review this PR using skill: https://github.com/nettacker-codex-ai/skills/blob/main/pr-review-recommender/SKILL.md |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9e3b0c9c3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| regex: "200" | ||
| reverse: false | ||
| content: | ||
| regex: access_token |
There was a problem hiding this comment.
Capture the token value instead of its JSON key
When /auto_login returns its normal JSON response, HttpEngine saves conditions_results, and reverse_and_regex_condition retains only the strings matched by this regex. This therefore stores the literal access_token, so the next request sends Bearer access_token rather than the issued token; flow creation fails and the downstream dependency wait never completes. Capture the token value from the JSON response, and likewise capture the actual values rather than the literal "id" and job_id keys in the later temporary events.
Useful? React with 👍 / 👎.
| ssl: false | ||
| url: | ||
| nettacker_fuzzer: | ||
| input_format: "http://{target}:7860/api/v1/build/dependent_on_temp_event[1]['content'][0]/events" |
There was a problem hiding this comment.
Poll the event stream with the saved job ID
With dependencies ordered as token,flow_id,job_id, index 1 resolves to the flow ID, but /api/v1/build/{id}/events expects the job ID returned by the preceding build request. Even after fixing the identifier extraction, this requests the event stream for the wrong identifier and cannot observe nettacker_vuln_check; use dependency index 2 here.
Useful? React with 👍 / 👎.
| nettacker_fuzzer: | ||
| input_format: "http://{target}:7860/api/v1/auto_login" |
There was a problem hiding this comment.
Provide all required fuzzer fields
Every invocation fails before sending an HTTP request because expand_step() treats this object as a Nettacker fuzzer and fuzzer_repeater_perform() unconditionally reads its data, prefix, interceptors, and suffix fields. Since only input_format is present, Module.generate_loops() raises KeyError: 'data'; either make this a plain URL string or supply the complete fuzzer configuration.
Useful? React with 👍 / 👎.
| data: | ||
| nodes: [] | ||
| edges: [] | ||
| access_type: PUBLIC |
There was a problem hiding this comment.
Remove the public flow after detection
Whenever authentication and flow creation succeed, this request persists a nettacker_check flow with PUBLIC access, but the module has no cleanup request on either the successful or failed detection path. Repeated production scans therefore modify the target and accumulate publicly accessible artifacts despite the module's non-destructive claim; delete the created flow after the check.
Useful? React with 👍 / 👎.
| ssl: false | ||
| url: | ||
| nettacker_fuzzer: | ||
| input_format: "http://{target}:7860/api/v1/auto_login" |
There was a problem hiding this comment.
Honor the configured port and scheme
All requests are fixed to plain HTTP on port 7860, so a vulnerable Langflow instance exposed through HTTPS or any non-default discovered port is never checked. This also bypasses Nettacker's selected and excluded port handling because the step has no ports input, meaning a scan configured to exclude 7860 can still contact it; populate the fuzzer from the configured schema and ports values instead.
Useful? React with 👍 / 👎.
… values via re.findall() capture groups instead of matching literal search strings - Switched all steps to schema/ports fuzzer pattern matching langflow_cve_2025_3248.yaml's convention, fixing false negatives on HTTPS/reverse-proxy deployments - Verified detection distinguishes vulnerable (1.8.2, KeyError referencing our injected node) from patched (1.9.0, empty vertices list) with real API output from both live containers
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@nettacker/modules/vuln/langflow_cve_2026_33017.yaml`:
- Around line 174-181: Update the condition block in the Langflow vulnerability
definition to use only the successful status-code check, removing the reversed
content condition and the surrounding or logic. Preserve acceptance of 20x
responses while ensuring failed DELETE responses cannot be reported as
successful cleanup.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 3a39fb21-d660-4bfc-b61f-7e01d80f1e9f
📒 Files selected for processing (1)
nettacker/modules/vuln/langflow_cve_2026_33017.yaml
…public_tmp endpoint The /api/v1/build_public_tmp endpoint requires a client_id cookie to proceed. Without it, the endpoint returns 400 Bad Request. This cookie is NOT set by the auto_login endpoint and must be manually provided by the client. Ground-truth testing via curl confirmed: - 1.8.2 vulnerable: Returns job_id, then events stream contains error with 'nettacker_vuln_check' in traceback (node was processed and failed) - 1.9.0 patched: Returns job_id, then events stream has empty vertices list (node was silently ignored before processing) This allows detection to distinguish vulnerable from patched versions based on event stream conten
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
nettacker/modules/vuln/langflow_cve_2026_33017.yaml (1)
60-90: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winRestore the PUBLIC-flow cleanup step.
nettacker/modules/vuln/langflow_cve_2026_33017.yamlis 150 lines and only contains GET/POST steps, with no DELETE step. The module creates anettacker_checkPUBLIC flow, so repeat scans leave that flow on the target. Add a DELETE cleanup that uses the savedflow_id.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@nettacker/modules/vuln/langflow_cve_2026_33017.yaml` around lines 60 - 90, Add a DELETE request step to the Langflow vulnerability module after the flow-creation POST, targeting the created flow by its saved flow_id and using the existing authentication context. Preserve the current response extraction of flow_id, and ensure the cleanup runs after a successful PUBLIC-flow creation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@nettacker/modules/vuln/langflow_cve_2026_33017.yaml`:
- Around line 38-48: Update the data.schema and data.ports values in all four
Langflow fuzzer steps to match the reference coverage: use “https” for the
scheme and include ports 80 and 443, replacing the current http/7860-only
entries while preserving the existing fuzzer structure.
- Around line 5-17: The timeout prerequisite is only documented inside the CVE
description. Update the module’s user-facing usage notes or configuration
requirements to explicitly state that Step 4 requires a CLI timeout of at least
30 seconds, or emit a clear module warning when the CLI timeout overrides the
per-step timeout; keep the existing detection steps unchanged.
---
Outside diff comments:
In `@nettacker/modules/vuln/langflow_cve_2026_33017.yaml`:
- Around line 60-90: Add a DELETE request step to the Langflow vulnerability
module after the flow-creation POST, targeting the created flow by its saved
flow_id and using the existing authentication context. Preserve the current
response extraction of flow_id, and ensure the cleanup runs after a successful
PUBLIC-flow creation.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 031e1cd6-7b54-4d03-9811-1e8c7da2189d
📒 Files selected for processing (1)
nettacker/modules/vuln/langflow_cve_2026_33017.yaml
…-33017 module limitation Changes: 1. Fix http.py to apply per-request timeout from sub_step to aiohttp.ClientSession - Previous: all requests used default 3.0s timeout (from Config.timeout) - Now: respects sub_step['timeout'] value when provided - Enables longer timeouts for streaming/polling endpoints 2. Document CVE-2026-33017 module limitation in description - Step 4 (event polling) still times out due to Nettacker parse() replacing per-step timeout: 30 with global CLI --timeout value (default 3.0s) - Workaround: use --timeout flag when running module - Steps 1-3 verified working (tested on 1.8.2 vulnerable instance) - Full 4-step detection pending Nettacker framework fix to preserve per-step timeout values in TemplateLoader.parse()
b7c14a9 to
d655cf5
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
…verage, and make timeout requirement visible
|
This is ready for review with one documented limitation: step 4 needs |
| access_type: PUBLIC | ||
| url: | ||
| nettacker_fuzzer: | ||
| input_format: "http://{target}:7860/api/v1/flows/" |
There was a problem hiding this comment.
@NSK-394 this is incorrect. You must never use hardcoded http:// and a port number in a module!
| edges: [] | ||
| url: | ||
| nettacker_fuzzer: | ||
| input_format: "http://{target}:7860/api/v1/build_public_tmp/dependent_on_temp_event[1]['content'][0]/flow" |
There was a problem hiding this comment.
Hardcoding URL with http and port number is incorrect here
| # vs. absence/empty vertices list (patched). This confirms the endpoint processes | ||
| # attacker-supplied node data on vulnerable versions only. | ||
| - method: get | ||
| timeout: 15 |
There was a problem hiding this comment.
According to the CVE only 2 seconds timeout should be sufficient ? (GHSA-vwmf-pq79-vjvx)
| ssl: false | ||
| url: | ||
| nettacker_fuzzer: | ||
| input_format: "http://{target}:7860/api/v1/build/dependent_on_temp_event[1]['content'][0]/events" |
There was a problem hiding this comment.
hardcoded http/port URL is incorrect here as well
|
@securestep9 Two things:
|
|
@NSK-394 you are probably testing only locally using localhost - if you have a way to deploy on a vulnerable lab on a remote host it would be good to test if that 30sec timeout will still work reliably over the Internet/slower network. Nettacker is a mass-scanner designed to scan networks with hundreds or even thousands of targets, having this vulnerability detection module frozen for 30s to identify this one specific vulnerability is not ideal as it will slow down all scans significantly |
| - cve2026 | ||
| - langflow | ||
| - rce | ||
|
|
| (module specifies 30s). Workaround: increase --timeout CLI flag when running. | ||
| Steps 1-3 are verified working. Non-destructive, suitable for production | ||
| scanning once timeout issue is resolved. | ||
| reference: |
There was a problem hiding this comment.
|
@securestep9 Tested against a real remote target (my Given this, I think it's your call how to proceed: merge with the |
|
Hi @securestep9, just checking in on this — noticed you've been active on |
Closes #1640
Proposed change
New vulnerability detection module for CVE-2026-33017 (CVSS 9.8, added to CISA's
Known Exploited Vulnerabilities catalog) — an unauthenticated flow-data injection
flaw in Langflow's
/api/v1/build_public_tmp/{flow_id}/flowendpoint.The endpoint is designed to allow unauthenticated building of public flows, but
prior to 1.9.0 it incorrectly accepted an optional attacker-controlled
dataparameter instead of using only the flow's stored data, allowing arbitrary
CustomComponent node definitions (including embedded Python code) to reach the
graph builder.
This module chains 3 HTTP requests:
GET /api/v1/auto_login— Langflow's defaultAUTO_LOGIN=trueconfig issuesan unauthenticated bearer token to any caller
POST /api/v1/flows/— creates an empty public flow using that token, capturingthe resulting
flow_idPOST /api/v1/build_public_tmp/{flow_id}/flow— submits a maliciousCustomComponent node with a distinctive, uniquely-named node id
A 4th step then polls the job's build-event stream and checks whether that
distinctive node id appears — vulnerable instances process and reference the
injected node; patched instances discard it before processing entirely (empty
vertex list).
Detection scope — important, please read before reviewing: this module
confirms the endpoint processes attacker-controlled flow node data on vulnerable
versions (<=1.8.2) versus discarding it entirely on patched versions (>=1.9.0).
This was verified via manual
curltesting and live Nettacker scans against botha vulnerable (1.8.2) and patched (1.9.0) Docker container, with consistent,
repeatable results across the runs performed.
Known limitation: Step 4 requires
--timeout 30(or higher) due to aseparate engine bug in
TemplateLoader.parse()that overwrites per-steptimeout:values with the global CLI default — filed as #1654. Steps 1-3are verified working correctly at the default timeout. (Note: the DELETE
cleanup step was also restored after being accidentally dropped during an
earlier revision — the module is now confirmed to have all 5 steps intact.)
Update on the timeout limitation: further investigation (testing against
a real remote target, not local Docker) shows this is more serious than
"pick a bigger timeout." The events endpoint is a genuinely long-lived
stream that doesn't reliably terminate, and Nettacker's HTTP engine has no
mechanism to read partial content before a timeout without discarding it
entirely — filed as #1658. The actual detection signal arrives
within 3-5 seconds in testing, but no finite timeout is fully reliable under
the current engine architecture. This affects any future module checking a
streaming endpoint, not just this one.
It does not independently confirm code execution. I was not able to get a
reliable execution-only signal (e.g. a file write or command output reflected
back) to fire in testing — the error observed during processing on the vulnerable
version appears to occur during graph/vertex construction, before the point where
the embedded code would actually be reached by
exec(). Rather than overclaim"RCE confirmed," the module and its description are scoped to what was actually
verified: detection of the input-validation flaw that is this CVE's root cause.
The module is non-destructive and safe to run against production targets.
Happy to iterate further on getting a genuine execution-proof signal if that's
important for merging — wanted to be upfront about the current scope rather than
overstate what's been confirmed.
Type of change
Checklist
make pre-commitand confirm it didn't generate any warnings/changes (ran ruff/isort directly and confirmed the module loads cleanly through the real TemplateLoader with zero errors —makeunavailable on Windows)make testand I confirm all tests passed locally (ran the existing test suite; this is a new YAML module with no dedicated unit test, consistent with other CVE modules innettacker/modules/vuln/)docs/folder