T09 · Insecure Skill Coding Practices
- Location
main.py:40- Finding
Unrestricted User-Controlled URL Fetch Enables Server-Side Request Forgery
- Content
View full analysis
Vulnerability Details
File Location:
main.py, lines 40-45
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: Mediumpython def get_document_info(self, url: str) -> Optional[Dict]: try: # Adding a small sleep to look more "human" time.sleep(1) response = self.session.get(url, timeout=30) response.raise_for_status() html = response.textTechnical Analysis
The skill describes
urlas an Issuu document URL, but the implementation passes the caller-controlled value directly torequests.Session.get()without validating its scheme, hostname, resolved IP address, or destination network.The
requestslibrary follows redirects by default. Consequently, an attacker may provide either a direct URL to an internal service or a public URL that redirects to a loopback, private, or link-local destination. The request is made from the environment running the skill and therefore inherits that environment's network reachability.The response body is not returned directly to the caller. The implementation instead searches it for an Issuu document identifier and returns a generic error when no identifier is found. This limits direct data disclosure, but does not eliminate SSRF: requests can still reach internal services, activate state-changing GET endpoints, and expose limited status or timing information through execution behavior and printed exceptions.
Attack Path
- An attacker invokes the skill with a URL targeting an otherwise inaccessible service, such as a loopback or private-network HTTP endpoint. Alternatively, the attacker supplies a public URL that redirects to such an endpoint.
run_skill()passes the URL toIssuuDownloader.download(), which passes it toget_document_info().get_document_info()callsself.session.get(url, timeout=30)without destination validation.- The Agent host sends the request using its own network privileges and routing conte ...[truncated 1166 chars]
- Remediation
View remediation
Remediation Suggestions
- Parse the supplied URL with
urllib.parse.urlsplit()and reject malformed values, embedded credentials, unexpected ports, and non-HTTPS schemes. - Enforce an explicit hostname allowlist containing only the Issuu domains required by the workflow, such as
issuu.comand specifically approved subdomains. Use exact hostname or properly bounded suffix comparisons rather than substring matching. - Resolve the hostname before connecting and reject every resolved IPv4 and IPv6 address that is loopback, private, link-local, multicast, reserved, unspecified, or otherwise non-global.
- Disable automatic redirects with
allow_redirects=False, or validate the scheme, hostname, port, and resolved addresses of every redirect target before following it. - Protect against DNS rebinding by ensuring the validated address is the address used for the connection, or enforce destination restrictions through a controlled outbound proxy or firewall.
- Apply egress filtering that prevents the skill from reaching loopback, private, link-local, metadata, and internal management networks.
- Return a clear validation error when the input is not an approved Issuu URL rather than attempting the request.
- Add automated tests covering direct private addresses, IPv6 loopback, alternative numeric IP representations, user-info URL tricks, attacker-controlled redirects, and DNS rebinding scenarios.
- Parse the supplied URL with
