T09 · Insecure Skill Coding Practices
- Location
scripts/fetch_article.py:42- Finding
Unrestricted Server-Side URL Fetching Enables SSRF
- Content
View full analysis
Vulnerability Details
File Location:
scripts/fetch_article.py:42, 181-184
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: MediumVulnerable Code
python response = requests.get(url, headers=headers, timeout=30)python url = sys.argv[1] output_json = '--json' in sys.argv result = fetch_wechat_article(url)Technical Analysis
The script accepts a URL from the command line and passes it directly to
requests.get()without validating the URL scheme, hostname, port, resolved IP address, or redirect destinations. Although the skill is primarily intended formp.weixin.qq.comarticles, its instructions explicitly permit attempts to summarize non-WeChat URLs.Because the
requestslibrary follows HTTP redirects by default, validating only the initial hostname would not be sufficient. An attacker could supply either a direct internal URL or an external URL that redirects to a loopback, private-network, link-local, or cloud metadata address.The response is also loaded fully into memory through
response.textwithout a response-size limit. This creates an additional denial-of-service risk when the target returns an excessively large body.Attack Path
- An attacker asks the agent to summarize a crafted URL.
- The URL points directly to an internal service, such as a loopback or private-network address, or points to an attacker-controlled server that redirects to such an address.
- The agent invokes
scripts/fetch_article.pywith the attacker-controlled URL. - The script issues the request from the host or container running the agent.
- If the response resembles parseable article content, portions may be extracted and printed. Otherwise, response-derived metadata or errors may still reveal information about the internal target.
- Repeated requests can be used for internal service discovery. A very large response may also consume excessive memory.
Impact Assessment
Successful exploitation ...[truncated 623 chars]
- Remediation
View remediation
Remediation Suggestions
-
Restrict accepted destinations to the skill's intended domain:
- Permit only HTTPS.
- Normalize the hostname before comparison.
- Allow only
mp.weixin.qq.com, or a narrowly documented set of required WeChat hosts. - Reject embedded credentials, unexpected ports, and malformed URLs.
-
Defend against DNS-based bypasses:
- Resolve all destination addresses before connecting.
- Reject loopback, private, link-local, multicast, unspecified, reserved, and other non-public address ranges for both IPv4 and IPv6.
- Ensure the connection uses the validated destination to reduce DNS rebinding risk.
-
Disable automatic redirects or validate every redirect hop with the same scheme, hostname, port, and resolved-address policy:
python response = requests.get( validated_url, headers=headers, timeout=(5, 15), allow_redirects=False, stream=True, )-
Enforce response controls:
- Require an expected HTML content type.
- Stream the response rather than loading it all at once.
- Stop reading after a strict maximum byte count.
- Set separate connection and read timeouts.
- Call
response.raise_for_status()before parsing.
-
Align
SKILL.mdwith the implementation's trust boundary. Remove the instruction to fetch arbitrary non-WeChat links, or route such links through a separately protected fetch service with equivalent SSRF controls. -
Add security tests covering direct private addresses, IPv6 loopback, alternative numeric IP representations, attacker-controlled redirects, DNS rebinding scenarios, unexpected ports, and oversized responses.
-
