Skip to content
Back to skills

Webapp Authorization Testing

ASecurity

Application-level authorization methodology - horizontal, vertical, and tenant boundary testing, ownership transitions, method and route differentials. Replay legitimate privileged requests with lower privilege using authz_matrix first to produce differential evidence.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
securitygobashtestinggitapifrontendbackendsecurity

Works with

  • api

Security analysis

A100/100

Scanned November 7, 2026

npx -y skills add bitbytelabio/arsenal --skill webapp-authorization-testing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Webapp Authorization Testing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Webapp Authorization Testing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/bitbytelabio-webapp-authorization-testing/badge)](https://www.skillsdirectory.com/skills/bitbytelabio-webapp-authorization-testing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: webapp-authorization-testing
description: Application-level authorization methodology - horizontal, vertical, and tenant boundary testing, ownership transitions, method and route differentials. Replay legitimate privileged requests with lower privilege using authz_matrix first to produce differential evidence.
domain: webapp
category: authz
hide: true
license: Apache-2.0
metadata:
  manifest_entry: src/corpus/webapp-authorization-testing/SKILL.md
---
# Authorization Testing

## Purpose

Test whether the application enforces WHO may do WHAT to WHICH object - at every boundary: same-level users (horizontal), privilege levels (vertical), tenants (organizational), and lifecycle states (ownership transitions). This is the methodology layer: it decides which pairs to replay and what counts as proof.

## Entry Conditions

- Any object-id parameter (/api/orders/1042), tenant header, or role-differentiated route is observed
- You hold accounts at two or more privilege levels, or two accounts in different tenants

## Core Strategy: Replay the Legitimate Request, Change Only the Identity

1. Perform the operation legitimately as the owner/rightful role (capture the exact request) - this is the **baseline**
2. Replay the identical request with a lower-privilege or different-identity context
3. Compare: status AND body AND effect on the object
4. **authz_matrix FIRST**: authz_matrix url=<resource> replays your request as the second configured account and as anonymous, then records the cross-identity access differential as exploit-proven ledger evidence. Do not hand-roll multi-account curl comparisons when authz_matrix settles it in one call.

## Boundary Classes

### Horizontal (user -> other user objects)
- A requests B objects across every resource type: profile, orders, messages, documents, settings, payment methods
- Both directions (A->B and B->A); write operations (PUT/DELETE), not just reads
- Confirm the returned data genuinely belongs to the other principal (match IDs/names/emails) - not a benign echo

### Vertical (lower role -> privileged functions)
- Replay exact legitimate privileged requests with the lower-privilege token: admin dashboards, user creation, settings, logs, export, backup
- The frontend hiding an admin menu is not access control - the backend route must be tested directly
- Method swap on protected routes (GET/POST/PUT/PATCH/DELETE) and override headers (X-HTTP-Method-Override, X-Original-Method) - gateways often authorize only the verb the UI uses

```bash
# Method differential on one protected endpoint, as the LOW-privilege user
for method in GET POST PUT PATCH DELETE OPTIONS HEAD; do
  code=$(curl -s -o /dev/null -w "%{http_code}" -X "$method" \
    -H "Authorization: $USER_TOKEN" "https://target.example.com/admin/users/5")
  echo "$method -> $code"
done
```

### Tenant isolation
- Tenant IDs appear in: path, query, JSON body, headers (X-Tenant-ID, X-Org-ID), nested resources (/orgs/{id}/projects/{id}/files/{id})
- Swap every occurrence; check each location separately - a request that ignores the body tenant_id but honors the path id has a half-enforced boundary
- Test cross-tenant via every route family: web UI, mobile API, legacy API, GraphQL, export/report endpoints
- Enumeration lead: sequential org/project IDs are guessable across tenants (candidate, not proof)

```bash
# Tenant-B data requested with Tenant-A session
curl -s -H "Authorization: $TENANT_A_TOKEN" \
  "https://target.example.com/api/organizations/tenant-b-id/users" | jq .
# Tenant supplied via header instead of path
curl -s -H "Authorization: $TENANT_A_TOKEN" -H "X-Tenant-ID: tenant-b-id" \
  "https://target.example.com/api/users" | jq .
```

### Ownership transitions (the forgotten states)
- Newly shared object: does the share revoke when the collaborator is removed?
- Transferred object: does the previous owner retain access?
- Revoked access: immediate or eventual enforcement?
- Removed team member: token/session still valid inside the tenant?
- Deleted user: their API keys, sessions, webhooks still active?

### Method and route differentials
- Same operation through /api/v1 vs /api/v2 vs /internal vs GraphQL mutation vs mobile endpoint - each must enforce the same checks
- Unauthenticated replay in addition to low-privilege replay: strip ALL auth headers

## Evidence Contract

```text
legitimate owner/role request (captured baseline)
-> identical request replayed by attacker identity
-> response differential (status/body identical to baseline = boundary broken)
-> the attacker actually received/changed the protected object (match identifiers)
-> report with both request pairs
```

Not enough: User A got HTTP 200. Good proof: User A received User B real protected object (same order ID, total, email), or the delete actually removed B document.

A 403 on one verb is NOT a clean negative until the other verbs, versions, and route families are covered.

## Common Misses

- Testing only reads; writes and deletes are where ownership checks are skipped
- Testing only the route family you crawled (web UI) - the mobile/legacy/GraphQL equivalent is often unprotected
- Forgetting ownership-transition states (share/revoke/transfer) - transient states leak access
- Nested-resource paths where the leaf check exists but an ancestor id is not validated (or vice versa)
- Referer-based or UI-flow authorization that the raw route ignores

## False Positives

- 200 with an empty list or an error body shaped like success - always verify the payload content matches the protected object
- 403 on GET but the finding requires testing writes before declaring the boundary enforced
- Cross-tenant 200 that returns YOUR tenant data re-serialized (id ignored, session tenant used) - that is correct enforcement, not a bypass
- Mass-assignment role changes belong to the mass-assignment specialist: prove the role field was persisted before reporting privilege escalation here

## Arsenal Tool Strategy

- authz_matrix url=<endpoint> - first call whenever an object-id or authenticated route appears; it records the differential as ledger evidence (report CWE-639 with the differential as proof)
- http_request - exact-request replay across identities
- browser_action - capture legitimate privileged flows (baseline corpus)
- record_hypothesis per boundary pair; claim and close systematically so coverage is visible in the ledger
- ffuf (bounded, -noninteractive, -maxtime) for hidden admin/functional routes the UI never links

## When to Load a Specialist Skill

- REST API object-level patterns -> `skill://webapp-testing-api-for-broken-object-level-authorization` (api-security); function-level -> `skill://webapp-api-bfla`
- IDOR enumeration technique -> `skill://webapp-exploiting-idor-vulnerabilities`
- Role via request parameters -> `skill://webapp-testing-api-for-mass-assignment-vulnerability`
- GraphQL-specific authorization -> `skill://webapp-graphql-api-security`
- Session/role-change behavior -> `skill://webapp-authentication-session-testing`

## Stopping Rule

Stop when: every discovered resource type has been exercised horizontally (read AND write), every privileged route family has a vertical replay across available roles, every tenant-id location has been swapped once, and each ownership transition has been driven once. When a boundary proves broken in one route family, still spot-check one alternative family (v1/v2, GraphQL) before closing - but do not exhaustively re-test every family for every object.

## Handoffs

- `skill://webapp-application-attack-surface-modeling` - where the boundaries came from
- `skill://webapp-business-logic-testing` - authorization rules that are business rules (spend limits, approval chains)
- `skill://webapp-application-data-exposure-testing` - over-fetch evidence

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.