concept Updated 2026-10-06

Worked Chains

Three real compound attacks, retold in component terms.

These are real findings retold as chains: each step shows what was observed, what capability it earned, and what that unlocked next. Read them the way you would map a target — as components, capabilities, and the playbooks that connect them. Targets are anonymized; the shapes are the lesson.

The invite-page write

Observation. An invite-acceptance page fired an API call on load, taking an invite code from the URL and placing it into the request path client-side.

The write. The code was not validated before being used as a path segment — and browsers collapse ../ sequences during request construction. The page's own authenticated session and CSRF token rode along with every request. Result: authenticated request forgery with an attacker-controlled path.

What it earned. With the email-change endpoint accepting the same JSON body shape the page already sent, the primitive became "change the victim's email" — no different-origin trickery required.

Escalation. With the email changed, a legitimate password reset delivered to the attacker. After login, the second-factor check used a truthy lookup on a plain object — so a prototype-chain value (like __proto__) passed the gate. Full account takeover.

The shape: a client-side sink that trusts a URL parameter → an authenticated primitive the app performs for you → an identity flow without re-authentication → a semantic bug in a gate.

The bridge

Observation. A support widget embedded in the main app, served from a second origin. A chat renderer that built HTML before sanitizing it, with a sanitizer hook permissive enough to let a single event handler through.

Step one. Self-XSS in the low-value widget frame — interesting to nobody, because who attacks themselves?

What it earned. JavaScript execution in the widget's origin. On its own: worthless.

The bridge. The widget communicated with the parent over postMessage, and the parent's origin check used substring matching — so an origin like support.site.attacker-domain.com passed. Worse, the parent exposed a debug channel that evaluated received code.

Escalation. From the compromised widget, one message through the bridge became DOM XSS in the main application. Then the legitimately embedded widget was used to send a crafted message as the victim — landing stored XSS in a support agent's session. frame-ancestors protections were irrelevant: the parent context was fully trusted.

The shape: a rare execution context in a low-value frame → a weakly checked trust bridge between contexts → execution where it counts.

Observation. An OAuth authorization endpoint validated the redirect_uri correctly — against a value stored in the session.

The quirk. A separate consent route re-read redirect_uri from the request instead, so the value that was validated and the value that was used came from different sources. (The validation was itself prefix-based, so a look-alike domain would also have passed.)

What it earned. The authorization code redirected to an attacker-controlled address.

Escalation. The code could be exchanged without a client secret, and it did not expire — making the interception a persistent backdoor rather than a one-shot.

The shape: one flow validates, a sibling flow trusts → parameter confusion → a token that outlives the moment it was stolen.

What to take from these

  • Identity flows are where "some execution" becomes "account takeover." Email change, password reset, OAuth — check for re-authentication and validation consistency every time.
  • Trust bridges amplify everything. postMessage handlers, iframes, subdomains: the origin check is the whole security model, and substring matching is not a check.
  • Small quirks decide chains. A truthy lookup, a client-side path sink, a consent route re-reading a parameter — none are impressive alone, all are pivotal in sequence.
  • Each step here could be a playbook. That is the point: map the components, write the trigger, let the engine carry you from one earned capability to the next.

What's next