T09 · Insecure Skill Coding Practices
- Location
examples/basic_example.py:39- Finding
Unbounded outbound HTTP requests can indefinitely block skill execution
- Content
View full analysis
Vulnerability Details
File Location:
examples/basic_example.py:39-57andexamples/basic_example.py:130
Additional Documentation Locations:SKILL.md:34,SKILL.md:39, andSKILL.md:47
Vulnerability Type: Outbound HTTP requests without timeouts or status validation
Risk Level: MediumVulnerable Code
python response = requests.get(search_url, params=search_params) search_data = response.json() pmids = search_data["esearchresult"]["idlist"] if not pmids: return [] # Step 2: Fetch paper details fetch_url = f"{base_url}/efetch.fcgi" fetch_params = { "db": "pubmed", "id": ",".join(pmids), "rettype": "abstract", "retmode": "xml" } response = requests.get(fetch_url, params=fetch_params) root = ET.fromstring(response.content)The bioRxiv request has the same issue:
python # Fetch data response = requests.get(url) data = response.json()The documented examples reproduce the insecure request pattern:
python response = requests.get(search_url, params=params)python response = requests.get(fetch_url, params={"db": "pubmed", "id": ",".join(pmids), "rettype": "abstract", "retmode": "xml"})python response = requests.get(url)Technical Analysis
Python Requests does not impose a network timeout unless one is explicitly supplied. Consequently, each
requests.get()call can wait indefinitely while establishing a connection or receiving a response. The implementation also does not callresponse.raise_for_status(), meaning HTTP error responses are passed directly to JSON or XML parsers.The destination hosts are fixed official PubMed and bioRxiv endpoints, which limits attacker control and prevents this issue from acting as arbitrary server-side request forgery. Nevertheless, an unavailable upstream service, a compromised network path, a malicious proxy, or a server that accepts connections but ...[truncated 1422 chars]
- Remediation
View remediation
Remediation Suggestions
Apply bounded connect and read timeouts to every outbound request, validate HTTP status codes before parsing, and handle network and parsing failures explicitly.
python import requests import xml.etree.ElementTree as ET try: response = requests.get( search_url, params=search_params, timeout=(5, 30), ) response.raise_for_status() search_data = response.json() except ( requests.Timeout, requests.ConnectionError, requests.HTTPError, requests.exceptions.JSONDecodeError, ) as exc: raise RuntimeError("PubMed search request failed") from excApply equivalent handling to the PubMed fetch and bioRxiv requests. Recommended additional hardening includes:
- Use separate bounded connect and read timeout values.
- Call
raise_for_status()before parsing every response. - Catch
requests.RequestException, JSON decoding errors, XML parsing errors, and missing response fields. - Use a
requests.Sessionwith a retry adapter that retries only safe transient failures, applies exponential backoff, and enforces a small retry limit. - Enforce a maximum acceptable response size before parsing large JSON or XML bodies.
- Preserve the fixed HTTPS endpoint allowlist and do not permit untrusted input to replace the scheme or host.
- Update all examples in
SKILL.mdso users do not copy the insecure request pattern.
