This vulnerability chains together three components that individually appear reasonable but collectively create a near-trivial path to admin session compromise. An unauthenticated attacker submits a crafted username in a failed login attempt. That username gets logged verbatim. The admin notification panel renders log entries using innerHTML. The result: stored XSS that fires when an administrator views notifications — giving the attacker their session cookie and full admin access.
What makes this noteworthy isn't the individual mistakes — it's the complete absence of any security-relevant decision required to exploit it. The attacker needs no authentication bypass, no special privileges, no technical sophistication. They submit a payload and wait. The failed login handler is functioning correctly. The logging is functioning correctly. The notification panel is functioning correctly. The vulnerability exists because each component was designed in isolation by different people at different times, none of whom saw the full data path from unauthenticated input to browser rendering.
The CSP on the admin panel likely permits inline event handlers, which means even basic XSS filtering at the logging layer wouldn't stop this — the attacker just uses an event handler attribute rather than a script tag.
Check your systems for this pattern: audit logs or logging infrastructure that renders to any web-based admin interface using innerHTML or equivalent unsafe DOM APIs. The key question is whether your logging pipeline treats data as untrusted at render time — not whether the logging itself sanitizes input, because that's the wrong layer. Audit logs are designed for machine consumption, and any feature that surfaces them in a browser UI crosses a fundamental trust boundary that likely wasn't explicitly reviewed.
The architectural fix is ensuring that data flowing from unauthenticated endpoints to admin-facing render paths is treated as untrusted at the rendering layer, regardless of what the data source is. This isn't about telling developers to be careful — it's about making the attack path structurally impossible, because the current pattern will recur in any codebase where components built at different times intersect without data provenance tracking.