Back to skill

Security audit

GitHub Extract

Security checks for vulnerabilities and agentic risk

Overview

This skill is meant to extract GitHub content, but its implementation can fetch and save content from arbitrary URLs, which is broader than users would expect.

Review before installing. Use only with trusted public GitHub URLs, and avoid passing arbitrary URLs or using --save until the skill enforces a GitHub-only allowlist, validates redirects, adds timeouts and size limits, and removes the original-URL fallback.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
gh_extract.py:63
Finding

Arbitrary URL Fetching Enables Server-Side Request Forgery

Content
View full analysis
str: # given a github url, return the raw url f = furl(url) host = "github.com" if f.host.lower() != host: logger.warning(f"Host is not {host}: {url}") return "" ``` ```python def save_github_url_to_file(url: str) -> Path: raw_url = get_github_raw_url(url) or url return save_url_to_file(raw_url) def extract_text_from_github_url(url: str) -> Path: raw_url = get_github_raw_url(url) or url return get_text_from_url(raw_url) ``` ```python def main(): args = cli() logger.remove() logger.add(sys.stderr, level=args.verbose and "DEBUG" or "INFO") if args.save: raw_url = get_github_raw_url(args.url) or args.url print(save_url_to_file(raw_url)) else: print(extract_text_from_github_url(args.url)) ``` ### Technical Analysis The Skill is documented as accepting GitHub URLs, and `get_github_raw_url()` appears to enforce that the input hostname is exactly `github.com`. However, invalid input causes the function to return an empty string. Every network-access path then uses the expression: ```python get_github_raw_url(url) or url ``` This restores the original, rejected, user-controlled URL. As a result, the hostname check does not establish an effective security boundary. In normal extraction mode, the arbitrary URL is supplied to `requests.get()`. In save mode, it is supplied to the external `wget` program. Redirect destinations are not restricted or revalidated. A public destination could therefore also redirect the request to an internal or otherwise prohibited address. This behavior exceeds the least privileges required to extract public GitHub content. The imp ...[truncated 1561 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
gh_extract.py:1
Finding

Mutable Runtime Dependencies Create a Supply-Chain Risk

Content
View full analysis
=3.10" # dependencies = [ # "furl>=2.1.4", # "loguru>=0.7.3", # "requests>=2.32.5", # "urllib3>=2.6.3", # ] # /// ``` The documented execution method invokes dependency resolution through `uv`: ```bash # print file content to stdout uv run --script ${baseDir}/gh_extract.py # save file to a temp path, with a proper filename uv run --script ${baseDir}/gh_extract.py --save ``` ### Technical Analysis The inline dependency declarations specify only minimum versions. They do not pin exact reviewed releases, provide artifact hashes, or use a committed lockfile. Running the script through `uv run --script` can consequently resolve and install dependency versions that were not present when the Skill was audited. No package name in the reviewed files is demonstrably malicious or typographically deceptive. The issue is therefore not evidence of an intentional malicious dependency. It is a supply-chain hardening weakness that allows the effective third-party code executed by the Skill to change over time. If a future compatible package release, transitive dependency, configured package index, or package-distribution account is compromised, malicious code could be introduced without modifying this project. ### Attack Path 1. The Skill is invoked using `uv run --script`. 2. `uv` resolves packages satisfying the open-ended lower-bound constraints. 3. A newer, compromised, or otherwise unsafe compatible release is selected from the configured package index. 4. The package is installed or loaded into the runtime environment. 5. Malicious package initialization or imported code executes with the same operating-system permissions and network acces ...[truncated 773 chars]
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (9)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 40)May include surrounding context.

md
- for repo/tree, will try to get `README.md` or `SKILL.md` or `README.txt`

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

When GitHub URL conversion fails, the code falls back to using the original user-supplied URL directly, allowing the skill to fetch arbitrary remote resources rather than only GitHub content. In an agent context, this can bypass intended scope restrictions and be abused for SSRF-like access to internal services or unauthorized retrieval of non-GitHub data.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill invokes shell commands and performs network retrievals, but it declares no explicit tool scope or permissions boundary. That makes its effective capabilities broader and less auditable, increasing the chance the agent can fetch remote content or write files without clear policy controls or informed user consent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger phrases are broad natural-language requests like extracting, downloading, or summarizing a GitHub URL, which can cause the skill to activate in situations where the user did not clearly intend remote retrieval or local file saving. Over-broad activation increases the risk of unexpected network access, content ingestion from untrusted repositories, and accidental execution of a higher-risk workflow.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill description explains that it converts GitHub URLs to raw URLs, fetches remote content, and may save files locally, but it does not warn users about those security-relevant side effects. Without an upfront warning, users may unknowingly cause the agent to retrieve untrusted remote content or write data to disk, which raises consent, provenance, and supply-chain concerns.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation claims the tool converts GitHub URLs to raw URLs and extracts content, but the implementation also fetches non-GitHub URLs directly. This mismatch is security-relevant because users and calling systems may rely on the narrower documented behavior while the code actually permits broader network access.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This skill’s stated purpose is to extract content from GitHub URLs, but the implementation uses wget to download and store remote content as a file. That behavior is broader than necessary, creates filesystem side effects, and can be abused to retrieve arbitrary remote payloads when combined with the fallback path that accepts non-GitHub URLs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill downloads remote content to the local filesystem without a clear user-facing warning or confirmation, despite the expected behavior sounding like simple text extraction. In an agent environment, silent file creation from user-controlled URLs can enable storage of unwanted or risky content and makes the skill more dangerous than its interface suggests.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

The code invokes an external downloader subprocess on a user-controlled URL without enforcing that the target remains a GitHub raw URL. While it does not use a shell, it still expands the skill’s capability from simple content extraction to arbitrary network fetch and file write behavior, increasing attack surface and enabling unintended downloads to local disk.

Content

Scanner excerpt · gh_extract.py (reported line 67)May include surrounding context.

python
tmpdir = Path(tempfile.mkdtemp(prefix="gh-extract-"))
    tmpdir.mkdir(parents=True, exist_ok=True)
    # work in tmpdir, let wget decide the file name
    subprocess.run(["wget", "--quiet", url], cwd=tmpdir)
    for path in tmpdir.glob("*"):
        # return the first file
        if path.is_file():

Static analysis

No suspicious patterns detected.