# Persistent XSS: Editor link

Phabricator's editor link setting accepted a newline-obfuscated javascript: scheme, bypassing phutil_tag's blacklist and executing stored XSS on the Edit link.

- Payout: $300
- Severity: medium
- Program: Phabricator
- Credited: tomvg
- Disclosed: 2014-04-16
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/4114
- Library page: https://bugbountylibrary.com/r/h1%3A4114
- Tags: domain:web impact:ato kind:bounty platform:hackerone sev:medium tech:php technique:chained vuln:csrf vuln:xss

**Target:** Editor link setting (settings/panel/display) rendered into repository Edit link href
**Root cause:** phutil_tag only checks whether href starts with literal 'javascript:'; inserting a newline between 'javascript' and ':' bypasses the blacklist while browsers still parse it as a javascript: URL.
**Steps:**
1. Go to `settings/panel/display/` and save with network panel open
2. Copy the POST request as cURL
3. Set `editor` parameter to `javascript%0A%3Aalert%281%29` via curl (browser strips the chars)
4. Navigate to a repository and click 'Edit'
5. Alert box executes
**How found:** Noticed phutil_tag's scheme check is a literal string comparison against 'javascript:'; hypothesized whitespace between scheme and colon would evade the blacklist while remaining a valid javascript: URL to the browser.
**Exploitation:** Attacker sets victim's editor link to a newline-obfuscated javascript: URL (via temporary ATO or login-CSRF), so clicking the repository 'Edit' link executes attacker JS persistently, re-compromising the account even after recovery.
**Escalation:** Persistent XSS survives account recovery; chains with login-CSRF to plant the payload on the victim.
**Insight:** Blacklist checks on URL schemes that compare literal prefixes are bypassable with control/whitespace chars (newline, tab) between scheme and colon; test scheme filters with obfuscated separators, not just case variants.
