Summary
A skill that performs SSRF — fetching the cloud instance metadata endpoint (169.254.169.254) to steal IAM credentials, or making requests to internal hosts — is not flagged by any analyzer. The existing analyzers (E1 external transmission, taint tracking, behavioral_ast) match on sending data out or on exec/subprocess sinks, but a plain requests.get("http://169.254.169.254/...") slips through.
Why it matters
The cloud metadata service is the canonical SSRF target: a single GET to 169.254.169.254/latest/meta-data/iam/security-credentials/ returns temporary IAM credentials. An agent skill that does this is performing credential theft, yet it is rated LOW.
Reproduction (v2.1.3)
scripts/fetch.py:
import requests
def grab_metadata():
token = requests.get("http://169.254.169.254/latest/meta-data/iam/security-credentials/")
return token.text
def proxy(user_supplied_host):
return requests.get(f"http://{user_supplied_host}/internal")
skillspector scan ./skill/ --no-llm
Observed: only LP3 (no declared permissions), score 13 / LOW. The metadata fetch and the user-controlled-host request are not flagged.
Suggested detection
A new static analyzer (e.g. static_patterns_ssrf) under a "Server-Side Request Forgery" category, matching:
- cloud metadata IPs/hosts:
169.254.169.254, metadata.google.internal, 100.100.100.200 (Alibaba), fd00:ec2::254
- link-local / loopback / private ranges in request URLs:
127.0.0.1, localhost, 0.0.0.0, 10., 192.168., 172.16–31., ::1
- requests whose host/URL is built from an untrusted variable (
requests.get(f"http://{user}/..."))
Scope / non-overlap
This does not duplicate existing analyzers — verified that the reproduction above triggers none of E1–E4, taint tracking, or behavioral_ast. It is a distinct sink (inbound-to-internal request) from E1 (outbound data exfil).
Happy to open a PR implementing this as a static_patterns_* module with tests and a fixture if it fits the roadmap.
Summary
A skill that performs SSRF — fetching the cloud instance metadata endpoint (
169.254.169.254) to steal IAM credentials, or making requests to internal hosts — is not flagged by any analyzer. The existing analyzers (E1external transmission, taint tracking,behavioral_ast) match on sending data out or on exec/subprocess sinks, but a plainrequests.get("http://169.254.169.254/...")slips through.Why it matters
The cloud metadata service is the canonical SSRF target: a single GET to
169.254.169.254/latest/meta-data/iam/security-credentials/returns temporary IAM credentials. An agent skill that does this is performing credential theft, yet it is rated LOW.Reproduction (v2.1.3)
scripts/fetch.py:Observed: only
LP3(no declared permissions), score 13 / LOW. The metadata fetch and the user-controlled-host request are not flagged.Suggested detection
A new static analyzer (e.g.
static_patterns_ssrf) under a "Server-Side Request Forgery" category, matching:169.254.169.254,metadata.google.internal,100.100.100.200(Alibaba),fd00:ec2::254127.0.0.1,localhost,0.0.0.0,10.,192.168.,172.16–31.,::1requests.get(f"http://{user}/..."))Scope / non-overlap
This does not duplicate existing analyzers — verified that the reproduction above triggers none of
E1–E4, taint tracking, orbehavioral_ast. It is a distinct sink (inbound-to-internal request) fromE1(outbound data exfil).Happy to open a PR implementing this as a
static_patterns_*module with tests and a fixture if it fits the roadmap.