How AI testing works

How AI agents test authorization: differential tests across accounts

How an AI pentest agent tests your app for IDOR and broken authorization: replay requests across accounts, compare responses, and prove the effect by read-back.

Short answer

An AI agent tests authorization by differential testing. It signs in as two or more test accounts, records what each can reach, then replays each request with the other account's identifiers and compares the results. A real flaw needs proof: a read of data the caller should not see, or a read-back that shows a change.

An AI agent tests authorization by differential testing: it compares what different callers can do with the same request. It signs in as several test accounts, replays each request under each account, and checks whether the server enforces the rules. The same method finds IDOR (insecure direct object reference), which OWASP's API list calls Broken Object Level Authorization.

What is differential testing for authorization?#

Differential testing sends the same action as different callers and compares the results. The difference, or the lack of one, shows whether access control works. A tester needs one baseline and several variants.

  • Baseline: the owner of an object makes a request. This shows what correct access looks like.
  • Variants: another account in the same role, an account in a lower role, an account in another tenant, and an anonymous caller make the same request.

If a variant gets the baseline response, the server did not enforce the rule. The first thing to rule out is that the data is public by design. For the manual version of this method, see our sister site's IDOR testing guide.

How does an AI agent run the test?#

The agent follows the same loop for any endpoint. In Incursion, a planner splits the engagement into tasks and workers run them in parallel. A worker handling authorization does this:

  1. Map. Sign in as each test account and record every request the app makes, including requests found in client-side JavaScript.
  2. Extract identifiers. List each object ID, tenant ID and role value that appears in paths, query strings and bodies.
  3. Build the matrix. For each endpoint, note which account owns which object.
  4. Replay. Send each request under each other account's session.
  5. Compare. Check status, body and headers against the baseline.
  6. Run controls. Repeat with nonexistent IDs, wrong record types and another account's token.
  7. Prove. For any candidate, read the effect back through the owner's session.
  8. Record. Save request, response and timestamp, and link them to the finding.

What does a worked differential test look like?#

The demonstration runs a read test, a write test with read-back, and the controls on a fictional app.

Demonstration: two-account authorization test on Harbor Notes

This is a demonstration on a fictional app, Harbor Notes, hosted on example.com. No real customer system was tested. Account A and account B are test accounts created for this example. Session values are shortened.

Setup. Account A owns note 1001. Account B owns note 2002. Both are "member" role in different workspaces.

Step 1: baseline (owner reads own note).

GET /api/notes/1001 HTTP/1.1
Host: harbor.example.com
Cookie: session=A-token
HTTP/1.1 200 OK
{"id":1001,"workspace":"ws-a","title":"Q4 plan","body":"Launch on the 14th"}

Step 2: variant (account B reads A's note).

GET /api/notes/1001 HTTP/1.1
Host: harbor.example.com
Cookie: session=B-token
HTTP/1.1 200 OK
{"id":1001,"workspace":"ws-a","title":"Q4 plan","body":"Launch on the 14th"}

B received A's private note. The body matches the baseline. This is a candidate finding.

Step 3: controls.

GET /api/notes/1001   (no cookie)            -> 401
GET /api/notes/999999 (B-token)              -> 404
GET /api/notes/2002   (B-token, B's own)     -> 200 (B's note)
GET /api/notes/1001   (C-token, third tenant)-> 200 (same body)

The anonymous control returns 401, so authentication works. The nonexistent ID returns 404, so the server does look up the record. Account C, in a third workspace, also reads note 1001. The failure is not tied to one pair of accounts.

Step 4: write test with read-back.

PUT /api/notes/1001 HTTP/1.1
Host: harbor.example.com
Cookie: session=B-token
Content-Type: application/json

{"title":"changed by B (test data)"}

HTTP/1.1 200 OK
{"ok":true}

The status alone proves nothing. The agent reads back through the owner's session:

GET /api/notes/1001 HTTP/1.1
Cookie: session=A-token
HTTP/1.1 200 OK
{"id":1001,"title":"changed by B (test data)", ...}

The title changed. The write is confirmed. The agent then restores the original title, because the record is test-owned data and the test must leave the app as it found it.

Result. Broken object-level authorization on read and write of /api/notes/{id}. Evidence: steps 2 and 4, controls in step 3.

Which test cases should an authorization run cover?#

Each row lists what to compare for one kind of flaw and what counts as proof.

Flaw Test Proof
Object-level (IDOR/BOLA) Account B requests account A's object ID Body holds A's data, and it is not public by design
Function-level (BFLA) Low-role account calls an admin-only endpoint Action succeeds, and a read-back shows the effect
Tenant isolation Account in tenant 2 requests tenant 1's object Cross-tenant data appears; a third tenant also reads it
Property-level User sends extra field such as "role":"admin" Read-back shows the field changed
Method switch Replace GET with PUT or DELETE on a protected path State changes on read-back
Version drift Call /v1/ after /v2/ is fixed Old version still returns the data

OWASP API5:2023 covers function-level flaws. WSTG-ATHZ-04 covers the web version of the object-level test.

What controls keep the agent honest?#

Controls stop the agent from calling a lenient server a vulnerable one. The controls in the demonstration are the ones we run: nonexistent identifiers, wrong record types, another account's token, and anonymous versus signed-in comparisons. The rule behind them comes from our evidence standard: a write is proven by reading the changed record back through another session.

Three more rules limit risk:

  • Destructive proofs use only test-owned accounts and records, marked as test data.
  • Tests of uploads, password guessing, email sending and paid third-party APIs are bounded, and the report states their cost.
  • A person reviews the evidence for each finding (human-in-the-loop pentesting).

AI pentesting false positives covers the failure modes these controls address.

What does an agent still miss?#

An agent cannot test a rule it cannot see. If your app lets a manager approve only invoices under a limit, the traffic does not state the limit. Give the tester an access matrix: roles, objects and the expected result for each pair. The accounts must also hold the right data. Testing signed-in flows covers account setup.

How AI pentesting works covers the full flow from scope to report. The example assessment shows a validated finding next to a rejected one.

Questions

Why does authorization testing suit AI agents?

The method is mechanical. The agent replays many requests under different accounts and compares results. That is repetitive work with a clear check. It does not replace the human step that decides whether a result breaks a business rule.

How many test accounts does an agent need?

At least two accounts in the same role to test object-level access, one account per role to test function-level access, and two tenants to test tenant isolation. An unauthenticated caller is the baseline for all of them.

Can the agent find authorization bugs if it has no access matrix?

It can find many by observation, because it records what each account sees. It cannot know the intended rule for every endpoint. A short access matrix from your team removes guesswork and cuts false positives.

Does a blocked cross-account request prove the endpoint is safe?

No. It proves that one request was blocked. Other methods, other parameters, older API versions and bulk endpoints can behave differently. The report states which paths were tested.

Sources

  1. OWASP API Security Top 10 2023: API1 Broken Object Level Authorization (checked 9 November 2026)
  2. OWASP API Security Top 10 2023: API5 Broken Function Level Authorization (checked 9 November 2026)
  3. OWASP Web Security Testing Guide v4.2: WSTG-ATHZ-04 Testing for Insecure Direct Object References (checked 9 November 2026)
  4. Excession Labs: Incursion (checked 9 November 2026)