Full Report
Using the drag and drop functionality with invalid data, innerHTML was being set. Johan Carlsson was approached about needing a CSP bypass on Github.com for this XSS in order to make it exploitable. Using things like autofilling credentials with a form didn't even work because the form-action was being set or css due to a strict allowlist. Github has three different XSS protections on the UI: CSP, form-specific CSRF nonces and the session sudo mode. Hotwire is an HTML over the wire framework to get HTML from the server side by observing what the page needs. The saw this was being used with the HTML element turbo-frame. By adding in a form with turbo-frame in it, Rails will listen for the inserted element and grab it from the backend dynamically for us. Since it was grabbed in a legit fashion, it also grabs the CSRF token. However, this only loads the form - we still need a way to add information to it. Using turbo-streams an attacker can modify the input forms with a click anywhere on the page and submit the form. The impact of passing CSRF protections is that an attacker can call any form-based request, such as add SSH keys. While messing around with this, they found a mechanism to remove the original two clicks. They found a piece of JavaScript that automates the clicking of an element! By passing in the function focusOrLoadElement, it's possible to force the page to click the various buttons for us. The world of CSP bypasses is much deeper than I realized! Using the hotwire framework to turn this into something more useful and the reuse of niche JavaScript functions was also interesting. Overall, a great post with a better discussion on the bug bounty podcast.
Analysis Summary
# Vulnerability: GitHub Content Security Policy (CSP) Bypass via Hotwire & Script Gadgets
## CVE Details
- **CVE ID:** Not explicitly stated in the text (Disclosed via HackerOne report #2246576)
- **CVSS Score:** ~8.3 (High/Critical - Based on unauthorized action performance)
- **CWE:** CWE-79 (Cross-site Scripting), CWE-693 (Protection Mechanism Failure)
## Affected Systems
- **Products:** GitHub.com
- **Versions:** Production environment prior to patch (April 2024)
- **Configurations:** Web UI components utilizing Hotwire/Turbo and specific "tag protection" settings.
## Vulnerability Description
The flaw originates from a "Self-XSS" in the Tag Protection settings where `innerHTML` was used to render error messages containing invalid user-supplied patterns without proper sanitization.
While GitHub’s strict CSP prevented traditional JavaScript execution (e.g., `alert(1)`), an attacker could bypass these protections by chaining "script gadgets":
1. **Turbo-Frames:** By injecting a `<turbo-frame>` element, the attacker forces the Rails backend to fetch a legitimate HTML form. Because the request is "same-origin," it includes valid form-specific CSRF nonces.
2. **Turbo-Streams:** Used to programmatically modify the fetched form's inputs (e.g., changing a public key field).
3. **Focus/Click Gadgets:** The attacker utilized a native GitHub JavaScript function `focusOrLoadElement` (a script gadget) to automate the clicking of the "Submit" button, bypassing the need for manual user interaction beyond an initial drag-and-drop.
## Exploitation
- **Status:** PoC available (demonstrated to GitHub via Bug Bounty)
- **Complexity:** High (Requires chaining multiple framework behaviors)
- **Attack Vector:** Network (Web-based)
- **User Interaction:** Required (Initially triggered via a Drag-and-Drop action)
## Impact
- **Confidentiality:** Low (Focus is on action performance rather than data exfiltration)
- **Integrity:** High (Attacker can perform state-changing actions: adding SSH keys, adding collaborators, or changing repository settings)
- **Availability:** Low
## Remediation
### Patches
- GitHub has patched the underlying `innerHTML` injection vulnerability in the `behaviors` JavaScript bundle.
- Hardening of the Turbo-frame/Hotwire implementation to prevent unauthorized cross-fragment manipulation.
### Workarounds
- Users should avoid dragging and dropping untrusted content into GitHub input fields.
- Ensure "Sudo Mode" (password re-authentication) is active for sensitive account changes, as this exploit cannot bypass that specific secondary prompt.
## Detection
- **Indicators of Compromise:** Unexpected SSH keys added to accounts; unauthorized repository invitations.
- **Detection Methods:** Audit logs for `public_key.create` or `repository.add_member` events originating from unexpected referrers or associated with unusual hash-fragment navigation (e.g., URLs ending in `#aaa`, `#bbb`).
## References
- **HackerOne Report:** hxxps[://]hackerone[.]com/reports/2246576
- **Hotwire Documentation:** hxxps[://]turbo[.]hotwired[.]dev/
- **Original Writeup:** hxxps[://]gist[.]github[.]com/joaxcar/6e5a0a34127704f4ea9449f6ce3369fc