fix(security): detect non-http schemes in shell-command SSRF scan#3252
Open
mohamed-elkholy95 wants to merge 1 commit intoHKUDS:nightlyfrom
Open
fix(security): detect non-http schemes in shell-command SSRF scan#3252mohamed-elkholy95 wants to merge 1 commit intoHKUDS:nightlyfrom
mohamed-elkholy95 wants to merge 1 commit intoHKUDS:nightlyfrom
Conversation
The shell-command scanner in ``contains_internal_url`` only matched http(s) URLs, but ``curl`` and ``wget`` support many more schemes, several of which have long histories as SSRF vectors: - ``file:///etc/passwd`` — local filesystem read - ``gopher://127.0.0.1:6379/_SET`` — the classic Redis SSRF - ``ftp://10.0.0.1/…`` — internal FTP access - ``dict://169.254.169.254/…`` — cloud-metadata probing The old regex ``https?://…`` silently let those through, so a prompt- injection-driven LLM emitting ``curl gopher://…`` cleared the exec guard and actually ran. This broadens the URL regex to any ``scheme://…`` form and moves the internal-target decision off of ``validate_url_target`` (which conflates "is this URL fetchable via http client?" with "does it target an internal host?"). The new helper ``_url_targets_internal`` is scheme-agnostic: ``file://`` is always internal, anything else is judged by whether the host resolves into a blocked range. Public hosts over non-http schemes (e.g. ``git clone ssh://git@github.com/…``) are unaffected.
c864c89 to
0eba798
Compare
This was referenced Apr 20, 2026
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
contains_internal_url(the scannerExecTooluses to reject commands targeting internal resources) only matchedhttps?://URLs, so the following slipped through and actually ran:curl file:///etc/passwd— local-file readcurl gopher://127.0.0.1:6379/_SET …— classic Redis SSRFcurl ftp://10.0.0.1/…— internal FTP accesscurl dict://169.254.169.254/info— cloud-metadata probingscheme://…form and splits the "targets an internal host?" decision into its own helper so the check is scheme-agnostic.file://is always treated as internal; everything else is judged by whether the hostname resolves into a blocked range.Changes
nanobot/security/network.py— broaden_URL_REto[a-z][a-z0-9+.\-]*://…; add_url_targets_internalhelper;contains_internal_urldelegates to it.tests/security/test_security_network.py— 5 new cases coveringfile://,gopher://,ftp://,dict://, plus a regression test thatgit clone ssh://git@github.com/…against a public host is not blocked.Backward compatibility
validate_url_targetis unchanged — WebFetch still only accepts http(s) URLs.curl http://169.254.169.254/…,wget http://localhost:8080/…) still block.ssh://git@github.com/…,https://example.com/…) still pass.Test plan
uv run pytest tests/security/test_security_network.py— 25 passuv run pytest tests/security tests/tools tests/agent— 862 pass, 0 failuv run ruff check nanobot/security/network.pyExecToolrejects the four bypass vectors and still allowscurl https://example.com/.Refs