# Stored XSS in blob viewer

Stored XSS in GitLab's OpenAPI blob viewer: SwaggerUI renders attacker HTML attributes in descriptions, enabling clickjacking and jQuery-ujs requests that bypass CSP.

- Payout: hidden
- Severity: medium
- Program: GitLab
- Found by: yvvdwf
- Disclosed: 2020-08-04
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/806571
- Library page: https://bugbountylibrary.com/r/h1%3A806571
- Tags: area:web domain:web impact:integrity kind:bounty platform:hackerone sev:medium tech:rest technique:chained technique:source-review vuln:xss

**Target:** OpenAPI/JSON blob viewer (SwaggerUIBundle)
**Root cause:** SwaggerUIBundle sanitizes malicious tags but leaves class, style, and data-* attributes in OpenAPI descriptions; GitLab does not re-sanitize the rendered output.
**Steps:**
1. Create file `xss-openapi.js` in any project with swagger 2.0 JSON whose info.description contains `<a href=... data-type=script data-remote=true class='atwho-view select2-drop-mask pika-select'></a><script>alert(0)</script>`
2. Open the file in the blob viewer so openapi_viewer passes data to SwaggerUIBundle
3. Click anywhere on the document; jQuery.globalEval executes the script and `alert(0)` fires
**How found:** Noticed GitLab routes OpenAPI files through SwaggerUIBundle, reasoned that SwaggerUI permits HTML in descriptions, and tested which attributes survive its sanitizer in GitLab's jQuery-ujs/CSP context.
**Exploitation:** Attacker commits a crafted OpenAPI file; victim views it, transparent overlay class intercepts clicks, and data-remote/data-type=script attributes cause jQuery-ujs to issue arbitrary GET/PUT/DELETE/HEAD requests with attacker parameters, with CSP bypassed via jQuery.globalEval.
**Escalation:** Chaining clickjacking overlay with jQuery-ujs data attributes to perform authenticated state-changing requests on behalf of the victim.
**Insight:** When a third-party renderer sanitizes HTML, enumerate which attributes it preserves (class/style/data-*) and cross-reference with the host app's JS frameworks (jQuery-ujs data-remote, globalEval) rather than only checking for script tags.

