# Researching Polymorphic Images for XSS on Google Scholar

Google Scholar rendered location.hash-selected templates unescaped and served user-uploaded images same-origin, enabling stored XSS via a polymorphic JPEG surviving re-encoding.

- Payout: $6,267
- Severity: high
- Program: Google
- Credited: Lorenzo Stella
- Disclosed: 2020-04-30
- Write-up quality: 8/10
- Original: https://blog.doyensec.com/2020/04/30/polymorphic-images-for-xss.html
- Library page: https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2020-04-30-polymorphic-images-for-xss-html
- Tags: domain:web impact:ato kind:research platform:research sev:high tech:rest technique:fuzzing technique:source-review vuln:file-upload vuln:xss

**Target:** Image upload endpoint and hash-based client-side templating on scholar.google.com
**Root cause:** Client-side templates fetched via XHR from location.hash were rendered unescaped, and user-uploaded images were served from the same origin; the image backend re-encoded uploads but preserved attacker-controlled bytes in the JPEG ECS segment.
**Steps:**
1. Observe Scholar screens render templates from `location.hash` via XHR, inserted unescaped into DOM.
2. Note image uploads are served same-origin, so an uploaded file's bytes can become HTML/JS.
3. Craft a base JPEG matching the server's re-encode quality factors, with 0-length-string EXIFs.
4. Embed payload in the ECS segment; find that first ECS bytes survive when separated by a `0x00`/`0x14` byte pattern.
5. Tune byte sequence so low-value bytes don't break the `<script>` tag in the browser.
6. Upload image, then point `location.hash` at the uploaded image URI to trigger XSS (onclick/mouseover handlers).
**How found:** Noticed the hash+XHR templating pattern rendering unescaped, combined with same-origin image hosting. When Google VRP doubted a polymorphic image could carry a valid payload, built a test suite comparing Imagemagick/GraphicsMagick/Libvips transformations to find bytes surviving re-encoding.
**Exploitation:** Attacker uploads a crafted JPEG whose ECS segment carries an XSS payload; the image survives Scholar's re-encoding and is served same-origin. A victim visiting a URL with a hash referencing the uploaded image causes the unescaped template renderer to execute the payload in scholar.google.com origin.
**Escalation:** Same technique yielded a second XSS on another endpoint, doubling the reward.
**Insight:** When an image backend re-encodes uploads, don't give up: build a differential test harness across the likely processing libraries and probe which byte regions (JPEG ECS, PNG iDAT, EXIF APPx) survive. Matching the output quality factors and using 0x00/0x14 separators let payload bytes persist through Huffman re-compression.
