# Reflected XSS in Tokopedia Train Ticket

Reflected XSS in Tokopedia train ticket search page bypassed a <.*> filter by splitting </script/ and > across two reflected parameters, enabling session theft.

- Payout: $210 (paid IDR 3000000)
- Severity: high
- Program: New Relic
- Credited: Jon Bottarini
- Disclosed: 2019-06-17
- Write-up quality: 7/10
- Original: https://visat.me/security/reflected-xss-in-tokopedia-train-ticket/
- Library page: https://bugbountylibrary.com/r/blog%3Avisat-me-security-reflected-xss-in-tokopedia-train-ticket
- Tags: domain:web impact:ato impact:data-leak kind:bounty platform:blog sev:high technique:param-pollution technique:source-review vuln:xss

**Target:** Train ticket search page (tiket.tokopedia.com/kereta-api/search) GET parameters reflected into JavaScript
**Root cause:** GET parameters are reflected into a JavaScript variable dataJs.query; a filter only encodes a parameter when it contains < followed by > in the same parameter, so splitting the closing tag across ori and dest bypasses it.
**Steps:**
1. Visit https://tiket.tokopedia.com/kereta-api/search/Jakarta-Gambir-GMR/Bandung-Bandung-BD?adult=1&infant=0&trip=departure&dep_date=16-09-2019&ori=GMR&dest=BD
2. Observe all GET params stored in JS variable dataJs.query
3. Note ori and dest use different encoding; > and < individually not encoded, but <> together is encoded
4. Split closing tag: set `ori=</script//` and `dest=><svg/onload=alert(document.location.href))//`
5. Load URL in Firefox; payload executes (Chrome XSS auditor blocks)
**How found:** Re-tested an old duplicate XSS report, fuzzed parameters, noticed ori/dest encoded differently and that < and > were only encoded when appearing together as <.*>; recalled the </script/> closing-tag bypass from an XSS payload repo and split it across two parameters.
**Exploitation:** Attacker crafts a URL with the split payload; victim clicking it executes attacker JS in Tokopedia origin. Although _SID_Tokopedia is HttpOnly, the session cookie is also stored in JS variable dataSession.session.cookies, so the XSS reads and exfiltrates the session, achieving account takeover.
**Escalation:** Chained XSS with the JS-exposed HttpOnly session cookie to steal the victim's session despite the HttpOnly flag.
**Insight:** When a filter only matches a pattern within a single parameter, look for multiple reflected parameters in the same sink and split the dangerous token across them; also check whether HttpOnly cookies are duplicated into JS-accessible variables.
