Open Graph / link-preview SSRF
SkillAI & modelsSSRF through link-preview / URL-unfurl / oEmbed features. Load when the app generates a preview card for a user-supplied URL: chat/forum/comment link unfurling, "add a link" in posts or profiles, oEmbed endpoints, rich-text editors that auto-embed, bookmark/save-for-later tools, or any UI that shows an Open Graph title/image/description for a pasted link. Signals: params like url=, link=, embed=, preview=; a "fetching preview" spinner; response JSON with og:title / og:image fields; User-Agents like *bot, *crawler, Slackbot, Discordbot, or a fetch from a different egress IP than the app.
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the Open Graph / link-preview SSRF skill
What this skill tells your AI
The instructions your AI receives, as published by noorqureshi/sploitagent in skills/web/web-open-graph-ssrf/SKILL.md and read by ahel’s review.
When it applies
The app unfurls user-supplied URLs — chat messages, comments, profile links, oEmbed consumers, "import bookmark", RSS/save-for-later. The dedicated fetch this triggers is an SSRF primitive, often with weaker filtering than the main app because previews must work for arbitrary third-party sites. Also applies when the preview is rendered by a headless browser (adds XSS-in-preview and local-file angles).
Why it works
Unfurlers are built to fetch anything, so allowlists are rare or trivially bypassed. The fetch frequently runs in a separate worker/microservice with its own network position — internal dashboards, metadata IPs, and queues may be reachable from there even when the web tier is locked down. The fetcher also parses the response (HTML, images, sometimes JS), which adds parser-differential bypasses the main app's URL validator doesn't share.
Method
- Find the unfurl path. Paste a URL to your
interactsh/Collaborator host into every link-accepting field. Watch for the OOB hit and fingerprint the fetcher: User-Agent, source IP (different ASN than the app = separate worker = different trust zone), and whether DNS and HTTP come from different IPs (DNS-rebinding candidate). - Probe internal reach with the standard SSRF matrix from
web-ssrf—127.0.0.1,169.254.169.254, RFC1918 ranges, common internal ports — but expect different results than app-tier SSRF: test the worker's neighbours, not the web server's. - Exploit the fetch-and-parse contract:
- Redirect chains — your URL 302s to
http://169.254.169.254/latest/meta-data/. Validators that check only the submitted URL pass; the worker follows. - OG-tag pivot — serve a page whose
og:image/og:urlpoints internal. Some fetchers re-fetch OG sub-resources with a second, unvalidated request. - Parser differentials —
http://allowed.com@internal/,http://internal#@allowed.com, scheme-relative and backslash variants (http:\\internal), IDN homographs. The validator and the worker's HTTP client often tokenize URLs differently. - DNS rebinding — validator resolves to a public IP, worker resolves again to
127.0.0.1. Reliable when the OOB hit showed separate DNS/HTTP sources.
- Redirect chains — your URL 302s to
- If the preview renders (headless browser): try
file:///etc/passwd,file:///paths to app config, and a page that fires JS to exfiltrate rendered internal content via OOB — renderer workers frequently run with broad network access. - Cache angle: previews are cached by URL. Check whether a poisoned preview (internal content, attacker HTML) is then served to other users who paste the same URL — stored impact without any victim-side script.
Gotchas
- Async unfurling — the fetch may happen seconds/minutes after submission, from a queue. Correlate by unique canary tokens per URL, not by timing.
- Image-proxy only — some apps only proxy
og:image, not the page fetch. A proxy that returns the fetched body is still full read-SSRF; one that re-encodes images is limited to port/host oracle via error vs. success vs. timing. - Allowlists exist where previews must look right —
oembedconsumers may restrict to known providers. Provider-side open-redirects and user-content subdomains (allowed.com.evil.comwon't fly;evil.com's redirect from an allowed provider URL will) are the way through. - Timeouts lie — internal closed ports often fail faster than filtered ones; a fast "no preview" vs slow "no preview" distinction maps internal services without any body.
- Rate limits on unfurl endpoints are usually tuned for UX, not scanning — slow down rather than trip the WAF and lose the worker's egress IP to a blocklist.
Verify success
OOB hit from an infrastructure IP you don't otherwise reach; a preview card whose title/image
came from an internal-only address (http://127.0.0.1:8080/ rendering an internal admin
title); metadata JSON in a preview; or a cached poisoned preview served to a second account.
References
PortSwigger SSRF research; bug-bounty writeups on chat-unfurler SSRF (Slack/Discord-style previews); Orange Tsai, "A New Era of SSRF" (parser differentials).
Signals
- GitHub stars
- 20
- Forks
- 7
- Last commit
- Sep 2026
Advanced
- Item type
- skill
- Key
web-open-graph-ssrf- Source
- github.com/noorqureshi/sploitagent
github.com/noorqureshi/sploitagent
Related picks
Skill · thedaviddias
The pick for JavaScriptmodern-javascript-patterns
Skill · wshobson
The pick for JavaScriptslack-gif-creator
Skill · anthropics
The pick for Slackslack-automation
Skill · davila7
The pick for Slackdiscord
Skill · anil-matcha
The pick for Discordmacmini-discord-reminder
Skill · bam-bam-2
The pick for Discord