
π― The plan
- Focus: Passive recon β manual testing of a legacy login β reflected XSS
- Time Spent: ~2 hours (OSINT + low-volume manual probing)
- Tools Used: subfinder / assetfinder / certspotter / waybackurls / gau (passive), curl + browser (manual)
NDA Disclaimer: The program is not disclosed, so this log is generic: no company name, no real domains, no endpoints, and no PoCs with live URLs. Everything technical is reproducible in an abstract form.
π§ The handler they forgot
What do you miss when your "possible attacks" filter blocks onclick and onmouseover? Exactly what an attacker needed: a handler you forgot. This session proved it on a legacy login: a reflected XSS that only requires the victim to open a link β no hover, no click, no interaction at all.
π Why blacklists always lose
Blacklist filtering is the classic defense that never quite wins. The idea sounds reasonable: block <script>, onclick, onmouseover... but the problem is that you must enumerate the past, while the attacker only needs one variant of the future.
- HTML is case-insensitive:
OnFocus,ONFOCUSandonfocusare the same thing to the browser. - There are over 100 event handlers; blocking a few leaves dozens open (
onfocus,onerror,onfocusin,onpointerenter,ontoggle,oninput...). - The filter reads the raw request; the browser parses the decoded DOM.
- New attributes and behaviors ship with every browser release.
The right fix is not filtering better: it is contextual output encoding (OWASP). The filter is only one layer of defense-in-depth, never the primary control.
βοΈ The discovery: attribute breakout, no angle brackets
The parameter was reflected inside an attribute of an <input>:
<input type="text" value="USER_INPUT_GOES_HERE">
For this context you don't need <script> or < >. Just break out of the attribute and add your own to the tag that is already open:
" autofocus onfocus=alert(1) x="
The browser renders it as:
<input type="text" value="" autofocus onfocus=alert(1) x="">
- The opening quote closes the
value. autofocusandonfocusbecome attributes of the already-open<input>β no angle brackets needed.- The trailing
x="swallows the leftover quote from the tag closing.
This is the canonical technique from PortSwigger's "Reflected XSS into attribute with angle brackets HTML-encoded" lab.
π The bypass: onfocus + autofocus = 0-click
The app's filter blocked onmouseover and onclick (handlers that require interaction) by returning a "possible malicious script" message. But it did not block onfocus.
On its own, onfocus still requires the user to click or tab into the field. That's where autofocus comes in: on page load, the browser focuses the element automatically, firing onfocus immediately.
Result: JavaScript execution with zero interaction, from a single malicious link.
Payload: " autofocus onfocus=alert(document.domain) x="
Delivery: the victim clicks the link β the payload fires on load.
Useful auto-trigger variants from the same family: onerror on <img src=x>, onload on <body>/<iframe>/<svg>, ontoggle on <details>, onanimationstart... PortSwigger's XSS cheat sheet has a curated "event handlers that do not require user interaction" section.
π‘οΈ The CSP that saved nothing
The response included a Content-Security-Policy... but with the classic escape:
Content-Security-Policy: default-src 'none'; script-src 'self' 'unsafe-inline'; ...
script-src governs all JavaScript, including inline event handlers (onfocus, onclick...), not just <script> tags. The 'unsafe-inline' token re-enables inline handlers β it undoes exactly what the CSP was trying to protect.
- A strict CSP with nonces/hashes would have blocked this vector.
- A CSP with
'unsafe-inline'(very common in legacy apps with inline scripts) does nothing against this. - The lesson: CSP is a second line of defense, it does not fix missing output encoding.
π‘ What worked, what didn't
- What paid off: Applying the generic attribute breakout instead of obsessing over
<script>. I enumerated the filter's handler family (by observing which ones it blocked) rather than guessing, andonfocusslipped through. - What tripped me up:
- The filter is inconsistent across contexts: in the login-submit POST flow it ended up "stripping" the handlers (the PoC stayed as
value="x""), while the GET vector reflected fully 3/3 times. Note: document reproducibility, don't oversell the bypass. - A call-stack leak on the filter's error page: out of scope for the program (stack traces/verbose errors). I left it out of the report.
- The filter is inconsistent across contexts: in the login-submit POST flow it ended up "stripping" the handlers (the PoC stayed as
- The takeaway: Blacklist β security. A filter that lists handlers is an enumeration game you cannot win; the attribute bypass with
autofocus + onfocusturns an XSS that "requires interaction" into a 0-click one, and sets it apart from a classic<script>PoC (often the difference between Low and Medium).
π From alert(1) to a real impact story
A pre-auth reflected XSS with HttpOnly cookie + CSP tends to land as Low/Informative or duplicate. To raise its level:
- Credential phishing on the login page: overlay/fake form on the same origin β harvest of username+password. Valid even with HttpOnly and CSP.
- Same-origin actions / ATO chain: read CSRF tokens from the DOM, change email β password reset β account takeover.
- UI redressing: spoofed warnings, MFA code capture.
- 0-click is the multiplier: "the victim only clicks a link and the payload fires with no interaction" β above any hover/click PoC.
β Final takeaways
- Takeaways (3):
- Blacklist filters are beaten with attribute breakout and an off-list handler (
autofocus+onfocus= 0-click). 'unsafe-inline'in CSP re-enables inline handlers β CSP does not save broken encoding.- A strong report narrates real impact (login phishing, ATO, 0-click), not just
alert(1).
- Blacklist filters are beaten with attribute breakout and an off-list handler (
- Your move: If you're testing a legacy target, don't dismiss the login as "boring": it's where people are conditioned to type credentials. Test the attribute, not the tag.
Note: For this post, I used AI tools to format the text, add emoticons and make corrections.




