June 8, 2026
Swagger UI HTML Injection — From “No XSS” to $450 Bounty
The Target
Mohamed Adel
2 min read
The Target
A developer-facing data annotation platform on a private bug bounty program. Standard recon surfaced an exposed Swagger UI at /apidocs/, which immediately caught my attention. Swagger UIs are notorious for one class of issue: the ?url= parameter.
The Finding
Swagger UI's ?url= (or ?config=) parameter accepts an external URL pointing to an OpenAPI spec. If there's no domain allowlisting, an attacker controls the entire spec — and with it, how the UI renders.
https://[REDACTED]/apidocs/?url=<ATTACKER_CONTROLLED_URL>https://[REDACTED]/apidocs/?url=<ATTACKER_CONTROLLED_URL>The spec I served injected raw HTML into the rendered page. The result: arbitrary HTML rendered under the legitimate target origin, visible to any user who clicks a crafted link.
The Triage Push — "Can You Escalate to XSS?"
The team's first response was a reasonable one:
"Could you demonstrate if this HTML injection can be escalated to Cross-Site Scripting (XSS)?"
Fair ask. HTML injection without JS execution often drops to Low or Informational. I dug in.
The Swagger UI bundle ships with DOMPurify, and it's configured properly — event handlers (onerror, onmouseover, etc.) and javascript: URIs are stripped before rendering. Direct XSS was not achievable.
At this point, many researchers close the tab and move on. I didn't.
The Pivot — Two Concrete Attack Chains
Instead of framing this as "XSS failed," I reframed it around what the HTML injection could do on its own:
PoC #1 — Credential Phishing via Fake Login Page
A fully functional fake login form rendered under the legitimate target origin. The victim's browser shows the real domain in the URL bar with a valid SSL cert. The injected HTML mimics a login prompt — username, password, submit. Credentials go to the attacker's server. This is a phishing vector that bypasses all URL-reputation checks because the origin is the trusted company domain.
PoC #2 — Open Redirect via OAuth2 Authorize Button
The Swagger UI's "Authorize" button behavior can be hijacked through the spec. By supplying a crafted authorizationUrl in the spec, clicking Authorize redirects the victim to an attacker-controlled domain — with the potential to capture OAuth tokens or credentials mid-flow.
Both PoCs demonstrated real-world exploitability without any JavaScript execution required.
The Result
- Status: Triaged ✅
- Severity: Medium
- Bounty: $450
Key Takeaways
- DOMPurify blocking XSS is not the end. HTML injection on a high-trust origin enables phishing attacks that are arguably more dangerous than reflected XSS against a dev subdomain, because the origin itself lends legitimacy.
- Concrete PoCs change severity outcomes. "HTML injection possible" is vague. "Functional credential-harvesting form rendered under a trusted corporate origin" is not. Always show the real-world scenario.
- Dispute duplicates precisely. A duplicate closure based on incorrect matching is worth pushing back on. One clear comparison table was enough to get this reopened.
- Dev subdomains matter. Dev tooling running on a trusted corporate origin is still in scope for high-impact attacks. Impact follows the origin, not the intended audience.
Happy hunting.
— Mo (@iamabdelaal on HackerOne)