# Clipboard DOM-based XSS

GitLab's pasteGFM handler trusted the text/x-gfm-html clipboard MIME type and set it as innerHTML, letting a malicious site inject JS via copy-paste into Markdown fields.

- Payout: hidden
- Severity: medium
- Program: GitLab
- Found by: vovohelo
- Disclosed: 2021-08-19
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/1196958
- Library page: https://bugbountylibrary.com/r/h1%3A1196958
- Tags: area:web domain:web impact:ato kind:bounty platform:hackerone sev:medium technique:source-review vuln:misconfiguration vuln:xss

**Target:** Markdown textarea paste handler (copy_as_gfm.js)
**Root cause:** pasteGFM reads the attacker-controllable text/x-gfm-html clipboard MIME type and assigns it directly to div.innerHTML without sanitization before converting to GFM.
**Steps:**
1. Host a page with `document.oncopy` handler calling `event.clipboardData.setData('text/x-gfm-html', 'XSS<img/src/onerror=alert(1)>')` and `event.preventDefault()`.
2. Victim selects text on the malicious page and copies it, poisoning the clipboard with the x-gfm-html payload.
3. Victim pastes into any GitLab Markdown field (e.g. new issue description) where pasteGFM runs.
4. pasteGFM sees no `text/x-gfm` but a `text/x-gfm-html`, creates a div and sets `div.innerHTML = gfmHtml`, firing the onerror handler.
**How found:** Code review of copy_as_gfm.js: noticed gfmHtml is read straight from clipboardData and assigned to innerHTML without sanitization, then built a copy-event PoC to confirm.
**Exploitation:** Attacker lures victim to a page that hijacks the copy event to write a malicious text/x-gfm-html payload; when the victim pastes into a GitLab Markdown editor, the unsanitized innerHTML assignment executes attacker JS in the GitLab origin, enabling actions via the JS API or credential harvesting. Noted as unexploitable on gitlab.com due to CSP.
**Insight:** Clipboard MIME types beyond text/plain are attacker-writable by any site via the copy event; audit paste handlers that read custom clipboard formats (text/x-gfm-html) and feed them to innerHTML rather than sanitizing.

