Skip to content

fix(tools): refuse a non-http orchestrator URL, as the sibling filter does - #429

Merged
Yambr merged 5 commits into
docs/demo-walkthroughfrom
fix/tools-reject-nonhttp-orchestrator-url
Aug 11, 2026
Merged

fix(tools): refuse a non-http orchestrator URL, as the sibling filter does#429
Yambr merged 5 commits into
docs/demo-walkthroughfrom
fix/tools-reject-nonhttp-orchestrator-url

Conversation

@Yambr

@Yambr Yambr commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Targets the branch behind #346, clearing one of its two Blocking semgrep findings.

The finding is real, and tracing it is what shows why

semgrep raises dynamic-urllib-use-detected (Blocking) on openwebui/tools/computer_use_tools.py. Traced to the source:

self.valves.ORCHESTRATOR_URL_MCPClient(url, ...)base → three urlopen call sites (health probe, MCP preflight, chat-scope read).

So it is not caller-controlled — it is an Open WebUI admin setting. That is the argument for calling it a false positive, and it is not enough, because:

The sibling file already refuses exactly this. openwebui/functions/computer_link_filter.py:330 checks the scheme and rejects anything but http/https, with a comment naming the same risk:

Only http(s) is a valid orchestrator transport. Reject file://, ftp://, data://, etc. — otherwise a misconfigured Valve could read arbitrary local files through urlopen (ruff S310).

Two paths consume the same Valve. One was guarded, one was not. That asymmetry is the defect — not the rule firing.

Where the check goes

The constructor, not the three call sites. The URL enters once and fans out; guarding the entry cannot later be applied to two of three places and missed on the third.

Probed both directions

URL accepted
http://localhost:8000 yes
https://orchestrator.internal yes
file:///etc/passwd no
ftp://host/x no
data:text/plain,hi no
/etc/passwd (no scheme) no

Scope

This clears one finding. #346 carries 14 total: the other Blocking one is on computer_link_filter.py — which, given the guard quoted above, is worth re-reading before assuming it needs a fix — plus 12 dangerous-subprocess-use-tainted-env-args across the journey harness, which are a separate argument about test-harness code driving docker from env.

… does

semgrep flags `dynamic-urllib-use-detected` on this file as Blocking, and
tracing it out is what makes the finding real rather than noise: the URL
comes from `self.valves.ORCHESTRATOR_URL`, an Open WebUI admin setting,
so it is not caller-controlled — but urllib honours file://, ftp:// and
data://, and there is no guard here at all.

The sibling function file already refuses exactly this, with a comment
naming the same risk: "a misconfigured Valve could read arbitrary local
files through urlopen (ruff S310)". So one of the two paths that consume
the same Valve was protected and the other was not. That asymmetry is the
defect, not the rule firing.

The check goes in the constructor rather than at each urlopen: the URL
enters once and fans out to three call sites (health probe, MCP
preflight, and the chat-scope read), so guarding the entry cannot be
partially applied later.

Probed both directions: http and https accepted; file://, ftp://, data:
and a bare path refused.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JCVG3p5zphDdsnCptx4S7J
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • main
  • next/v1

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7882d25c-392c-46d3-941e-938bb85a281a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Yambr

Yambr commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

Reviewed and approved on the merits; blocked on the base, not this diff.

SCA — trivy (filesystem) is red here, and #346 fails the same gate already (along with SAST — semgrep and Trivy). This PR inherits that — its diff is 13 lines of Python adding a urlparse scheme check and touches no dependency. It sits behind #346's triage, which is the right order: this fixes ONE of #346's 14 semgrep findings.

Review outcome: merge-worthy. Second reviewer verified the guard sits at the single entry point with all three urlopen sites downstream, allowlist not denylist, and urlparse lowercasing so HTTP:// passes.

Correction to my own reasoning: I argued "the sibling file guards it." That is precedent — it defeats the "false positive, admin-controlled" reading by showing the repo already judged this risk real for this Valve. But the load-bearing argument is the privilege boundary: a WebUI admin who can edit Valves is not thereby entitled to read files inside the container, and file:// through urlopen hands them exactly that, laundered into tool output. That holds with zero siblings.

@Yambr
Yambr force-pushed the fix/tools-reject-nonhttp-orchestrator-url branch from 7f36c56 to f0a2fe7 Compare August 11, 2026 08:41
widemoat-ai and others added 4 commits August 11, 2026 12:26
…ions

The refusal shipped without a test, so an implementation that accepted every
scheme — or refused every one, including http — would have passed.

Four cases: http and https construct, `file:///etc/passwd` raises (the scheme
that turns a network read into a local-file read and reports it as if it had
come from the orchestrator), ftp/data/gopher raise, and a bare `host:port`
with no scheme raises here rather than deep inside urlopen with a message
naming neither the Valve nor the URL.

Mutation-checked: neutering the check to `if False` reds five of them, so the
positive and negative halves are both bound to the guard rather than to
whatever the constructor happens to do.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… client

The constructor check closed three urlopen sites and left a fourth open:
`_resolve_chat_scope_sync` builds its own Request straight from
ORCHESTRATOR_URL and never constructs an `_MCPClient`. So the PR's own claim —
that the check sits where the URL enters — was not true of every entry.

That path is the worse one. It catches every exception and degrades to the
base scope, so a `file://` Valve would have read a local file and reported the
result as a scope, and any failure would have looked like an ordinary resolve
miss. The check is now a module-level helper both entry points call, and the
async `_resolve_chat_scope` reaches it by delegating to the sync method.

The first version of these tests was VACUOUS: without the guard, urlopen
raises on the bad scheme, the method degrades, and the return value is the
base scope either way — so asserting the return value proved nothing. They now
assert whether urlopen was REACHED, which is what the guard changes, and carry
the control that an http URL still is attempted — otherwise a guard refusing
everything would pass.

Mutation-checked both directions: removing the guard reds three cases,
refusing every scheme reds the control.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The comment said urlparse gives `orchestrator:8000/mcp` an empty scheme. It
reads `orchestrator` as the scheme, so the case is refused for the same reason
ftp:// is. The assertion was right and its stated mechanism was not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Yambr
Yambr merged commit 55e87e6 into docs/demo-walkthrough Aug 11, 2026
10 checks passed
@Yambr
Yambr deleted the fix/tools-reject-nonhttp-orchestrator-url branch August 11, 2026 09:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants