security: hard-gate chat-invoked URL ingestion on real user intent (VULN-13906 2/4)#2145
Draft
edwinjosechittilappilly wants to merge 3 commits into
Conversation
…ULN-13906 PR2/4) The URL Ingestion Tool (Langflow URLComponent in flows/openrag_url_mcp.json) trusted whatever URL the model passed as a tool argument, so a poisoned document's hidden instructions could drive a server-side fetch even though the user never asked for one. Reuse the existing backend-injected Langflow-global-variable mechanism (the same one used for OPENRAG_INGEST_*) to pass the real current chat message into the flow as OPENRAG_CURRENT_USER_MESSAGE, and refuse the fetch in ensure_url() unless the requested URL is actually present in that trusted value. flows/components/url.py is newly extracted (via scripts/extract_flow_component.py) since the URL component previously had no checked-in source; it's kept in sync with the flow JSON via scripts/update_flow_components.py as usual. upload_context_chat sets the trusted value to only the upload-confirmation framing text (never the document body itself), so a URL embedded in the uploaded document can never satisfy its own intent gate. The non-chat Knowledge API URL-submit path is unaffected — it has no chat message to gate on, and treats the explicit submission itself as confirmed intent (allowlist/SSRF checks land in PR3).
Contributor
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ 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 |
…ent methods (VULN-13906 PR2 follow-up) The intent-gate global added in the previous commit resolves via Langflow's load_from_db mechanism, which requires the variable name to be listed in LANGFLOW_VARIABLES_TO_GET_FROM_ENVIRONMENT and given a baseline placeholder default (same as the existing OPENRAG_INGEST_* vars) — otherwise the field never resolves and the intent check silently no-ops. Wire it into docker-compose.yml, the Helm chart (values.yaml + langflow-dotenv.yaml), and the operator's DefaultLangflowEnvVars, so the gate actually functions regardless of deployment method.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Part 2 of 4 for VULN-13906. Stacked on #2144 (PR1 fencing) — this PR's diff should be reviewed against that branch, not
main.ensure_url()(LangflowURLComponent,flows/components/url.py) now refuses to fetch a URL unless it's actually present in the real current chat user message — not just whatever the model passed as a tool argument.OPENRAG_INGEST_URL/OPENRAG_INGEST_TOKEN):chat_service.pyinjectsX-Langflow-Global-Var-OPENRAG_CURRENT_USER_MESSAGEset from the real request, never from retrieved/uploaded content or model output.flows/components/url.pyis newly extracted fromflows/openrag_url_mcp.json(no checked-in source existed for this component before) viascripts/extract_flow_component.py, and kept in sync viascripts/update_flow_components.py.upload_context_chatsets the trusted value to only the synthetic "I'm uploading a document called '...'" framing — deliberately not the document body — so a URL embedded in a poisoned upload can never satisfy its own intent gate. This is the exact scenario from the pentest report.Test plan
tests/unit/test_chat_service_url_intent_header.py—langflow_chatsets the header from the real prompt;upload_context_chatsets it to upload-framing text only, excluding the document body (poisoned-doc URL never appears in the trusted value)tests/unit/test_flow_url_intent_gate.py— intent check runs before the SSRF check inensure_url(); the new input is present and synced acrossurl.py⇄openrag_url_mcp.json(template entry +field_order)tests/unitsuite — same 18 pre-existing failures asmain/PR1, no new failures