Skip to content

feat(analyzer): no detection for SSRF / cloud-metadata credential theft #62

@CharmingGroot

Description

@CharmingGroot

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 E1E4, 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions