Skip to main content

AuthzTrace - authorization contract testing for IDOR and BOLA

PyPI Python CI OWASP API #1 Marketplace MIT Stars

How it works · Quickstart · Contract · CI guarantees · Roadmap

How it works

flowchart LR
    Contract["1. Contract<br/>actors + IDs + endpoint rules"]
    Matrix["2. Generate matrix<br/>endpoint x ID relationship x actor"]
    Safety["3. Safety gate<br/>record unsafe skips + preflight allow rows"]
    Replay["4. Live API<br/>replay executable deny rows"]
    Verdict{"Match contract?"}

    Setup["Exit 2<br/>invalid or untrustworthy setup"]
    Finding["Exit 1<br/>BOLA, leak, or strict warning"]
    Clean["Exit 0<br/>no failing executed checks<br/>warnings and skips stay visible"]

    Contract -->|valid| Matrix
    Contract -->|invalid| Setup
    Matrix --> Safety
    Safety -->|preflight fails| Setup
    Safety -->|passes| Replay
    Replay -->|request error| Setup
    Replay -->|response| Verdict
    Verdict -->|violation or strict warning| Finding
    Verdict -->|pass or non-strict warning| Clean

    classDef input fill:#161b22,stroke:#58a6ff,color:#f0f6fc,stroke-width:2px;
    classDef process fill:#1f2937,stroke:#8b949e,color:#f0f6fc;
    classDef decision fill:#221b2e,stroke:#d2a8ff,color:#f0f6fc,stroke-width:2px;
    classDef failure fill:#3d1519,stroke:#f85149,color:#ff7b72,stroke-width:2px;
    classDef success fill:#102a18,stroke:#3fb950,color:#56d364,stroke-width:2px;

    class Contract input;
    class Matrix,Safety,Replay process;
    class Verdict decision;
    class Setup,Finding failure;
    class Clean success;

What AuthzTrace does

AuthzTrace is an authorization contract test runner for REST APIs. You describe test identities, object ownership, and expected access once. AuthzTrace expands every endpoint across each owned object and declared actor, including anonymous actors you explicitly define.

GET /invoices/inv_A -> 200 means nothing by itself. When the contract says inv_A belongs to Alice, the same 200 for Bob is a proven BOLA.

You declare AuthzTrace generates CI receives
Actors and credentials Every endpoint x object x declared actor request A reproducible authorization verdict
Owners and scalar or named fixture IDs Owner, cross-user, nested-relationship, and anonymous checks SARIF findings with stable fingerprints
Endpoints and access rules Status and response-leak assertions Exit codes that separate findings from broken setup

Quickstart

Install the CLI and scaffold a contract from an OpenAPI document:

pip install authztrace
authztrace init --from openapi.yaml

The OpenAPI command is a starting point, not authorization inference. It scaffolds single-object routes, nested routes with multiple path parameters, and query parameters named id / object_id. Review the generated ownership and access rules before running it.

Point base_url at a running non-production API, then add stable test-object IDs and actor credentials. Secrets can stay in environment variables:

export ALICE_TOKEN="..."
export BOB_TOKEN="..."

authztrace run -c authztrace.yaml --sarif authztrace.sarif

No OpenAPI document? Start from the working example.

Run it in GitHub Actions
permissions:
  contents: read
  actions: read
  security-events: write

steps:
  - uses: actions/checkout@v4

  # Start your API here, or point base_url at a reachable test environment.
  - uses: Asttr0/AuthzTrace@v0.5.0
    env:
      ALICE_TOKEN: ${{ secrets.ALICE_TOKEN }}
      BOB_TOKEN: ${{ secrets.BOB_TOKEN }}
    with:
      config: authztrace.yaml
      sarif: authztrace.sarif

  - uses: github/codeql-action/upload-sarif@v4
    if: ${{ always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }}
    with:
      sarif_file: authztrace.sarif

The contract

This contract says Alice and Bob each own one invoice. Owners may read their own invoice; every other identity must be denied without receiving the owner's marker.

base_url: https://api.test.example.com

actors:
  alice: { auth: { type: bearer, token: "${ALICE_TOKEN}" } }
  bob:   { auth: { type: bearer, token: "${BOB_TOKEN}" } }
  anon:  { auth: { type: none } }

resources:
  invoice:
    ids:     { alice: inv_A, bob: inv_B }
    markers: { alice: "Alice private", bob: "Bob private" }
    endpoints:
      - request: GET /api/invoices/{id}
        allow: [owner]
        assertions:
          allow_contains: ["{marker}"]
          deny_not_contains: ["{marker}"]

policy:
  deny_status: [401, 403, 404]

That single endpoint becomes six checks: one endpoint x two owned objects x three declared actors. Alice and Bob must retrieve their own marker; the other user and anon must receive a deny status and never see it.

Object IDs can also live in query parameters, headers, JSON, or form bodies. Endpoint allow rules accept owner, named actors, authenticated, anonymous, all, or *.

Test nested parent/child ownership

Name each ID and set target_id to the protected child:

resources:
  org_user:
    target_id: user_id
    ids:
      alice: { org_id: org_A, user_id: user_A }
      bob:   { org_id: org_B, user_id: user_B }
    endpoints:
      - request: GET /api/orgs/{org_id}/users/{user_id}
        allow: [owner]

For Alice, AuthzTrace checks (org_A, user_A) as allowed and requires denial for (org_A, user_B), (org_B, user_A), and (org_B, user_B). Named IDs work in paths, queries, headers, JSON, and form bodies. See the complete nested example.

Runtime login flows

Actors can acquire credentials from the API before preflight instead of receiving a static token. Each actor gets an isolated HTTP session, and a failed login or missing credential aborts the run as untrustworthy setup with exit code 2.

actors:
  alice:
    auth:
      type: login
      request: POST /api/login
      json:
        username: alice
        password: "${ALICE_PASSWORD}"
      extract: { from: json, path: session.access_token }
      credential: { type: bearer }

extract.from accepts json, header, or cookie. JSON extraction uses a dotted path; header and cookie extraction use name. The resulting credential can be applied as bearer, header, or cookie, and expect_status can override the default 2xx login expectation. OAuth-style form payloads, separate HTTP(S) identity-provider URLs, redirect control, and custom token schemes are supported.

Login requests are explicit setup operations and therefore run before the read-only endpoint safety gate, including POST logins. Keep targets pointed at controlled non-production environments. See the authentication guide and complete login-flow demo contract.

Built for trustworthy CI

Behavior Guarantee
Credential preflight Every executable allow row must pass before deny rows run. Broken credentials or fixtures cannot produce a false green.
Read-only default Only GET, HEAD, and OPTIONS execute automatically. Other methods are visibly skipped unless marked safe: true or enabled with --include-unsafe.
Leak detection A denied response still fails if it contains a forbidden marker or JSON field.
CI-native reports Terminal, SARIF, JSON, and JUnit output; SARIF includes stable fingerprints for GitHub code scanning.
Flexible authentication Static Bearer, custom-header, cookie, and Basic credentials; anonymous actors; and isolated request-and-extract login flows. Actor credentials are excluded from reports.
Exit Meaning
0 No failing findings among executed checks; warnings and skipped unsafe rows remain visible
1 BOLA, response leak, or strict warning
2 Untrustworthy setup: bad credentials, unreadable owner fixture, invalid contract, or unreachable API

Current scope

AuthzTrace is alpha software focused on REST authorization regression testing with stable fixtures and static or runtime login credentials. It supports scalar objects and nested parent/child ownership; method-override, predictable-ID, mass-assignment, and GraphQL coverage remain planned. See the authorization test corpus for the full status.


Found AuthzTrace useful? Star the repository so more API teams can find it.
MIT © 2026 Mohamed Taha Slimani · @Asttr0 · Issues

Release files for authztrace 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for authztrace 0.5.0
File Size Uploaded
authztrace-0.5.0.tar.gz 33.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for authztrace 0.5.0
File Interpreter ABI Platform
authztrace-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 58.7 kB

Release files / authztrace-0.5.0.tar.gz

Download URL authztrace-0.5.0.tar.gz
Size 33.2 kB
Tags Source
SHA-256 checksum
How to use checksums
ee4bc0609853d9c3da35ea9ee7a151c4e95f4a4be6b98f06c5e3d6611c4646e5
BLAKE2b-256 checksum
How to use checksums
620c234a60c2de71a7be7949d77a78961b76d24c7e6dd9b091814b1ea7d58395
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 12, 2026.

Transparency log

Release files / authztrace-0.5.0-py3-none-any.whl

Download URL authztrace-0.5.0-py3-none-any.whl
Size 25.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
86f655743dc65508d2c797865a3990ce211ed86bdd0223a278e61712bd7e9884
BLAKE2b-256 checksum
How to use checksums
59bbe63f0d852026070628952ee4ead2c3a40276750d74d79591e19d94bbca64
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 12, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.0

2 release files

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page