# Escalate Auth Bypass

> Turn a suspected or confirmed authentication/authorization bypass into impact — admin access, session takeover, privilege escalation, or cross-tenant read. Use when you find a missing auth check on a route, a weak JWT verifier, a session cookie that's predictable or reusable across users, a privilege field client-controllable, or an audit finding tagged CWE-287/CWE-863/CWE-639. Walks from probe to admin-equivalent capability and persists a finding with the highest-impact action you reached.

- Skill: `vigolium/escalate-auth-bypass` (Agent Skill)
- Install (CLI): `npx skillmds@latest add vigolium/escalate-auth-bypass`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vigolium/escalate-auth-bypass/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- License: MIT
- Author: vigolium (https://skillmd.com/u/vigolium)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/vigolium/escalate-auth-bypass

---


# Auth Bypass → Impact Escalation

You have a suspected auth weakness. Your job is to turn it into the
strongest impact you can demonstrate — admin access, cross-tenant data
read, token forgery, or session takeover — and persist a finding with the
specific action that proves it. Reporting "missing auth check" without
showing what it gets you is not a finding.

## When this skill applies

- A route responds 200 with no `Authorization` / session cookie when it
  should require auth (compare to a known-auth'd record's response).
- JWT verification accepts `alg: none`, a key-confused HMAC secret, or a
  token signed with the public key as HMAC secret.
- A session ID is predictable (sequential, time-based, or short).
- A request body / query has a role/tenant/user field that, when changed,
  changes the response (`role=user` → `role=admin`, `tenant=A` → `tenant=B`).
- Audit harness flagged CWE-287, CWE-862, CWE-863, CWE-639, CWE-284, or
  CWE-639 — even theoretical.

## Workflow

### 1. Establish baselines

Use `list_auth_sessions` to see which auth contexts already exist for the
host. Use `auth_session_lookup` to pull the actual headers for at least
two roles if you have them (`anon` + `user` is enough; `user` + `admin`
is ideal). `remember` the role boundaries as `auth-roles`.

If only one role is available, use `query_records` to find an
unauthenticated record for the same endpoint to anchor the no-auth
baseline.

### 2. Classify the weakness

Pick **one** mechanism to attack — don't shotgun:

- **Missing auth on route**: pick the suspect endpoint, send the request
  with `replay_request` and `extra_headers: {}` to strip cookies. If you
  still get the privileged response, the route doesn't check auth at all.
- **Weak JWT**: decode the token (base64 each segment). Look at `alg`,
  `iss`, `aud`, `exp`, `sub`, custom claims (`role`, `tenant`). Re-mint:
  - `alg: none`: build header `{"alg":"none","typ":"JWT"}`, keep payload,
    drop signature (empty 3rd segment).
  - Key confusion: sign HMAC with the public key as the secret.
  - Empty / weak HMAC secret: try `""`, `secret`, `key`, the app name.
- **Session prediction**: collect 5-10 valid session IDs from `query_records`
  on login responses. If they're sequential, time-encoded, or short
  hex/base64, forge a neighboring ID via `replay_request`.
- **Privilege field client-controlled**: send the request with the role
  field flipped (`role=admin`, `is_admin=true`, `tenant_id=<other>`).

### 3. Confirm escalation, don't stop at "different"

A 200 with different content is *suspicious*, not proof. Confirm with
ONE of:

- The response body contains data the original role couldn't see (admin
  email, another user's email, a hidden flag).
- A privileged action succeeds: `DELETE /api/users/X`, `POST /api/admin/X`,
  `GET /api/users/all` returns a list of more than just the current user.
- A subsequent request using the forged session is accepted as that user
  (look up the user's email or role in the response).

Send the **smallest privileged request that proves the boundary was
crossed**. `remember` it with key `auth-bypass-proof` and include the
exact request line.

### 4. Map the blast radius

Briefly enumerate the surface the bypass unlocks. Don't enumerate at
scale — show:

- 1 admin-only endpoint reachable.
- 1 cross-tenant record visible.
- 1 sensitive write that succeeds (if write paths exist; do **not**
  destructively delete or modify real data — read or create-with-rollback
  if possible).

This sizes the severity in the finding without spamming requests.

### 5. Persist the finding

Call `report_finding`:

- `severity`: `critical` if you reached admin or full cross-tenant; `high`
  for same-tenant privilege escalation or read of another user's data.
- `title`: name the mechanism and the proven action — `"JWT alg=none
  accepted; forged admin token reads /api/admin/users (1234 users)"`.
- `cwe_id`: CWE-287 (auth missing), CWE-863 (broken auth check),
  CWE-639 (IDOR-style), CWE-345 (insufficient verification of data),
  CWE-347 (weak signature) — pick the one that matches the mechanism.
- `description`: 3 sentences. Mechanism, proof, blast radius. Include the
  decoded JWT header / forged session ID / mutated field value in the
  description body so the reproduction is unambiguous.

If the audit harness already raised this, `update_finding` to triaged
status referencing the new proof.

## Pitfalls

- Do not perform destructive writes (`DELETE`, `PUT` overwriting,
  password resets) on someone else's account. Read-only proofs are
  sufficient for severity.
- A forged token that returns 200 with an empty body proves nothing.
  The body must contain data the original role didn't have access to.
- Some apps return 200 with `error: "unauthorized"` in the JSON body —
  read the body, not just the status, before claiming bypass.
- If the app has a "demo admin" account that's publicly accessible by
  design, that's not a bypass — confirm by checking documentation or
  a comment in the code (`--source` mode).
- IDOR (object-level missing auth) is a related but distinct pattern —
  if your finding is "can read another user's order by changing the
  ID", use `idor-blast-radius` instead.

## Output expectations

- One `report_finding` with the strongest proven impact.
- A `remember` note with the canonical bypass request.
- Plan item marked `done`.

