fix(input): download the raw file for GitHub and GitLab /blob/ URLs - #566
Merged
Merged
Conversation
The input handler already routes a forge "/blob/" URL to the file download path instead of a clone, but it downloaded the URL as given. On github.com and gitlab.com that URL is the HTML file viewer, so the scan analysed the forge's page markup as the skill: scanning a clean SKILL.md through its GitHub /blob/ URL reported a 286 KB SKILL.md and DO_NOT_INSTALL. Rewrite those URLs to the raw file (raw.githubusercontent.com for GitHub, /-/raw/ for GitLab) before downloading. Hosts stay inside the existing download allowlist, and other URLs are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: kevin9327 <5299031+kevin9327@users.noreply.github.com>
rng1995
approved these changes
Sep 16, 2026
rng1995
left a comment
Collaborator
There was a problem hiding this comment.
[SkillSpector Review]
Approved at 875e6ccdcc3467806b947eb0a8b9c8c77e32a791.
I reviewed the complete change and its surrounding input-resolution, SSRF-validation, redirect, filename, and transitive-budget paths. The rewrite is narrowly scoped to the canonical GitHub and GitLab /blob/ file-page shapes, keeps both resulting hosts inside the existing download allowlist, and preserves the existing byte, time, redirect, and artifact limits. The parameterized tests cover both forges through the direct and workflow-budget paths and verify that the saved artifact contains the raw file rather than viewer HTML. The branch is based on current main, and all reported CI checks pass.
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.
Problem
The URL you get when you open a file on GitHub is its
/blob/page. Scanning a skill through that URL analyses GitHub's HTML file viewer instead of the file. NVIDIA's ownskill-inspectorskill, scanned three ways (live,--no-llm --format json,mainat4148ab3):The last row saves the 286 KB page under the name
SKILL.md, and the findings are about GitHub's page markup. GitLab behaves the same way:https://gitlab.com/gitlab-org/gitlab/-/blob/master/README.mddownloads a 49,355-byte page and reportsP9, while its/-/raw/URL gives the 5,869-byte file and no findings.Cause
InputHandler._is_git_urlalready sends a forge URL containing/blob/to the file-download path rather thangit clone._download_filethen fetches that URL as-is. On github.com and gitlab.com a/blob/URL answers200 text/htmlwith the viewer page, so nothing downstream can tell it apart from a real file.Fix
_raw_file_urlrewrites the two forge file-page shapes before either download branch runs:https://github.com/<owner>/<repo>/blob/<ref>/<path>->https://raw.githubusercontent.com/<owner>/<repo>/<ref>/<path>https://gitlab.com/<namespace>/<project>/-/blob/<ref>/<path>->.../-/raw/<ref>/<path>Both targets are already in
ALLOWED_DOWNLOAD_HOSTSand still go through_validate_url_host. Neither needs a redirect, so the directInputHandler()path (which does not follow redirects) works as well as the budgeted graph path. Every other URL, including/raw/,/tree/and repository URLs, is returned unchanged.Tests
tests/unit/test_input_handler.py::test_file_page_url_downloads_the_raw_filecovers GitHub and GitLab, each through a plainInputHandler()and one carrying aWorkflowResourceBudget(the pathresolve_inputuses). It uses anhttpx.MockTransportthat serves the skill only at the raw URL and an HTML page for anything else, and asserts the single request went to the raw URL and the savedSKILL.mdhas the skill's bytes.Before the fix (Windows 11, Python 3.12.10):
After:
4 passed. Every added line runs intest_input_handler.py,test_input_handler_ssrf.pyandtest_input_handler_bounds.py(checked with branch coverage). The pass-throughreturn urlis hit by the existing raw.githubusercontent.com download tests.The live scans above, re-run on this branch:
Suite
pytest -m "not integration and not provider" -p no:randomly, same machine:maintests/unit,tests/opencode,tests/test_*.pytests/nodesThe +4 are the new cases. The failures and errors are identical on both sides and Windows-only (release and
compare_scan_accuracyharnesses, CRLF fixtures, a backslash inside a POSIX file name, and parametrized test IDs over the Windows environment-variable length limit).ruff check src/ tests/: All checks passed.ruff format --check src/ tests/: 246 files already formatted.This touches
_download_fileonly, notresolve(), so it does not overlap with the/tree/handling proposed in #561.🤖 Generated with Claude Code