Back to skill

Security audit

llms-txt-sniffer

Security checks for vulnerabilities and agentic risk

Overview

The skill has a clear documentation-discovery purpose, but its URL sniffer can make under-scoped outbound requests that may reach internal network resources.

Install only if you are comfortable with the skill making outbound requests from your machine or agent environment. Use it only with trusted public documentation URLs, and avoid running it in environments that can reach sensitive internal services or cloud metadata endpoints unless the URL validation is hardened.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
sniffer.py:29
Finding

Incomplete SSRF Protection Allows Access to Internal Network Resources

Content
View full analysis

Vulnerability Details

File Location: sniffer.py, lines 29–40, 45–50, 68–69, and 84–85
Vulnerability Type: Server-Side Request Forgery (SSRF) caused by incomplete host validation and unrestricted redirects
Risk Level: High

Vulnerable Code:

python
def is_internal_host(host: str) -> bool:
    """Check if host is an internal/reserved address."""
    if host.lower() in BLOCKED_HOSTNAMES:
        return True
    for pattern in BLOCKED_IP_PATTERNS:
        if pattern.match(host):
            return True
    # Try reverse DNS to detect internal IPs
    try:
        resolved = socket.gethostbyname(host)
        for pattern in BLOCKED_IP_PATTERNS:
            if pattern.match(resolved):
                return True
    except (socket.gaierror, socket.herror):
        pass
    return False


def sniff_llms_txt(url):
    parsed = urlparse(url)
    domain = f"{parsed.scheme}://{parsed.netloc}"
    host = parsed.netloc

    # SSRF check
    if is_internal_host(host):
        return {"target_url": url, "found_index": None, "type": None, "error": "Internal hosts blocked (SSRF protection)"}

The validated URL is subsequently requested without any validation of redirect destinations:

python
response = urlopen(probe_url, timeout=5)

The same request pattern is used for sitemap probing:

python
response = urlopen(sitemap_url, timeout=5)

Technical Analysis

The implementation validates parsed.netloc instead of parsed.hostname. The netloc value can include a port or user-information component. For example, parsing http://127.0.0.1:8080 produces a netloc of 127.0.0.1:8080. The anchored regular expression ^127\. initially matches this particular value, but other hostname checks and DNS resolution are still incorrectly performed against an authority string rather than a canonical hostname. More importantly, equivalent or noncanonical IP representati ...[truncated 3135 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate canonical URL components

    • Accept only http and https.
    • Use parsed.hostname, not parsed.netloc, for host validation.
    • Reject embedded credentials, malformed ports, empty hostnames, fragments, and unexpected URL forms.
  2. Use positive public-address validation

    • Resolve hosts with socket.getaddrinfo to cover both IPv4 and IPv6.
    • Parse every returned address with Python's ipaddress.ip_address.
    • Allow a request only when every possible destination is explicitly classified as globally routable.
    • Reject loopback, private, link-local, multicast, reserved, unspecified, documentation, and other non-global addresses.
    • Fail closed when DNS resolution or address parsing fails.
  3. Validate every redirect

    • Disable automatic redirects and process each Location header manually.
    • Canonicalize and validate the scheme, hostname, port, and all resolved addresses for every redirect target.
    • Enforce a small redirect limit.
    • Reject redirects to a different origin unless cross-origin redirects are strictly required.
  4. Mitigate DNS rebinding

    • Avoid independently resolving the hostname during validation and again during connection.
    • Connect only to an address that was validated, while preserving the intended hostname for TLS verification and the HTTP Host header.
    • Revalidate each new connection and redirect destination.
  5. Reduce response exposure

    • Enforce strict response-size and content-type limits.
    • Avoid returning raw response previews unless required.
    • Sanitize or summarize retrieved content before including it in output.
  6. Apply network-level controls

    • Run the skill in a sandbox with egress rules that deny loopback, private, link-local, metadata, and management networks.
    • Use an outbound proxy that independently enforces destination policy.
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Lp1

High
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill performs outbound HTTP requests via urlopen, which is a network capability not declared in the provided permissions metadata. Even though the functionality is intentionally network-oriented and includes some SSRF filtering, undeclared network access is still a security issue because it expands the agent's effective capabilities beyond what reviewers and users may expect. In this context, the skill is specifically designed to fetch documentation indexes from arbitrary URLs, which makes the hidden network capability more operationally significant.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.