# Unvalidated handler name dispatch

Caller-supplied handler or method names reaching a privileged dispatcher without allowlist validation

_Area: Web access control and IDOR. Seen in 2 disclosed reports; latest 2026-08-12. Updated 2026-11-01._

## How it works
A dispatcher picks which privileged function to run based on a name the caller supplies (a POST field, a postMessage action, a DOM value). The code assumes the name is one of the safe, intended handlers, but nothing enforces that. When the name is resolved dynamically against an object or controller, the caller can reach internal methods the author never meant to expose, running them with the victim's or the system's privileges.

## Where it shows up
- Two entry points to the same dispatcher (e.g. an AJAX header path and a POST body path) where only one applies a name regex [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-j5jq-cr68-v2xx.md)
- Dynamic method resolution like `obj[method].apply(...)` on a page- or message-controlled string [E2](https://bugbountylibrary.com/r/h1%3A389108.md)
- Controllers that conditionally null out `$requiredPermissions` for one "public" action, leaving sibling methods reachable [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-j5jq-cr68-v2xx.md)
- Client buttons that read a value from the DOM and interpolate it into a request URL [E1](https://bugbountylibrary.com/r/h1%3A837328.md)
- Cross-user channels (WebSocket form-update, collaboration events) that can write into another user's DOM nodes [E1](https://bugbountylibrary.com/r/h1%3A837328.md)

## How to review
Find every dispatcher and confirm the invariant: the handler name is checked against a strict allowlist (e.g. `on[A-Z][\w+]*`) on *every* entry point, not just one. Diff parallel paths (header vs body, popup vs page) for identical validation [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-j5jq-cr68-v2xx.md). For dynamic resolution, confirm the resolved key is constrained to a fixed set, not arbitrary object properties [E2](https://bugbountylibrary.com/r/h1%3A389108.md). For DOM-driven requests, confirm the value is validated before URL interpolation and that no cross-user channel can mutate it [E1](https://bugbountylibrary.com/r/h1%3A837328.md). Check that permission checks cannot be conditionally disabled for one action while exposing others.

## Variants seen
- POST `_handler` field bypassing the regex enforced on the AJAX header path [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-j5jq-cr68-v2xx.md)
- Extension content script forwarding page postMessage action names into background `_fetch` [E2](https://bugbountylibrary.com/r/h1%3A389108.md)
- WebSocket form-update writing attacker values into a collaborator's DOM, then a trusted click builds a traversable URL [E1](https://bugbountylibrary.com/r/h1%3A837328.md)

## Impact and severity
Led to authenticated users invoking protected controller methods (password reset) [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-j5jq-cr68-v2xx.md), credentialed cross-origin requests from an extension origin [E2](https://bugbountylibrary.com/r/h1%3A389108.md), and arbitrary authenticated POSTs as another user [E1](https://bugbountylibrary.com/r/h1%3A837328.md). Severity rises when the dispatcher runs with elevated privilege or the victim's session, and when a trusted user action (a click) launders the attacker's input.

## Why fixes fail
Validating only one of two entry points leaves the other open; the AJAX path was guarded while the postback path was not [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-j5jq-cr68-v2xx.md).

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A837328.md
- E2: https://bugbountylibrary.com/r/h1%3A389108.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-j5jq-cr68-v2xx.md
