The Second Bug in the Field Next Door
The first XSS got fixed. The neighbouring field had its own — a different context, a different payload, the same account takeover.
Target anonymized · a construction-industry B2B platform
After one cross-site scripting bug in a profile field was patched, the tempting conclusion is "XSS: done." It rarely is. The lesson of this one is that XSS is a class, and classes hide in the neighbours. (Exploit kept defanged.)
The spark
The first bug lived in one profile field and reflected into an HTML context. Right beside it was a related field — a business name — and I wanted to know if it was handled by the same code or its own. So I put a probe in it.
Digging in
It had its own sink, and a different one: this value landed inside a script context, not HTML. That changes everything about the payload. HTML-context tricks were useless here; I needed something that broke out of the surrounding script safely. Once I found the shape that did, I had execution in the victim's origin again — through a field the first fix never touched.
"We fixed the XSS" almost always means "we fixed that input, in that context." The class survives in every input the patch didn't visit.
The exploit (defanged)
The account-takeover chain is the same family as the first: script running in the victim's origin drives the OAuth flow in a controlled window, captures the returned authorization artifact, and replays it to establish a session as the victim. I'm describing it, not shipping it — the value here is the audit lesson, not a weapon.
Impact
A second, independent path to account takeover in an app that had just been "fixed," reachable through a normal profile field.
The fix
Output-encode per context everywhere user input is rendered — HTML, script, attribute, URL — and treat an XSS report as a prompt to sweep the whole class, not to patch a single field.
All identifiers, targets and payloads in this post are anonymized or defanged. Findings were reported and resolved through responsible disclosure.