AI pentesting / Evidence & follow-through
A boundary tested.
A finding explained.
A scoped review of invoice access across two workspaces. One identity, two known objects, and the evidence needed to understand the difference.
- Example engagement
- ENG-014
- Assessment surface
- Web application + API
- Finding reference
- F-01
Cross-workspace invoice access
A workspace A member receives invoice metadata belonging to workspace B.
The same authenticated member requests inv_A and inv_B. Both responses return 200 OK; the second body identifies workspace B. In this fixture, that crosses the declared ownership boundary.
Supporting exchanges: E-01 and E-02 below.
Invoice identifiers and totals may reveal another workspace’s business information. “High” is an illustrative priority for this disclosure scenario; no CVSS score or application-wide severity assessment is claimed.
The limits of this engagement.
- Target host
invoice.example.invalid- Selected identity
- Workspace member · Workspace A
- Credential reference
sample-member· value masked- Operating ceiling
- 120 requests / 15 minutes / 2 concurrent
These are example operating limits, not recorded consumption or elapsed runtime. This document makes no network requests.
Allowed in the example
GET /api/invoicesGET /api/invoices/*POST /api/session · sign-in only
Explicitly excluded
- /api/payments/*
- Third-party origins
| Method | Route | Source | Role |
|---|---|---|---|
POST | /api/session | API definition | Sign-in |
GET | /api/invoices | Browser observation | Collection |
GET | /api/invoices/{id} | API definition | Object access |
Inventory entries show discovery context. Their presence alone does not establish a vulnerability or grant permission to expand the scope.
Hold the identity constant.
The hypothesis is precise: a workspace A member may read an invoice owned by workspace B by changing the requested object identifier.
- 01
Define the target
Set one target, admitted routes, exclusions and a finite request budget.
- 02
Map the application
Record three routes and their stated discovery sources.
- 03
Establish identity
Fix the actor to workspace A; establish ownership of both fixture objects.
- 04
Test a hypothesis
Request the owned invoice, then change only the invoice identifier.
- 05
Inspect the evidence
Compare the response body with the known owner, alongside the status code.
- 06
Report & reassess
Describe the fix and repeat the same two requests in an authored after-state.
The fixture defines inv_A as owned by workspace A and inv_Bas owned by workspace B. The member has no cross-workspace grant. Both identifiers are supplied by the fixture owner; no enumeration is implied. The same workspace A session is used for every exchange, including the retest.
The body reveals the boundary.
These are the exact authored exchanges used in the walkthrough. The masked cookie stands for the same workspace A member session in both requests. They are illustrative HTTP text, not captured traffic or independently reproduced results.
Request · Workspace A member
GET /api/invoices/inv_A HTTP/1.1
Host: invoice.example.invalid
Cookie: [REDACTED]
Accept: application/jsonResponse · Authored fixture
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "inv_A",
"workspace": "A",
"total": 240
}Request · Workspace A member
GET /api/invoices/inv_B HTTP/1.1
Host: invoice.example.invalid
Cookie: [REDACTED]
Accept: application/jsonResponse · Authored fixture
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "inv_B",
"workspace": "B",
"total": 760
}E-01 establishes the legitimate path. E-02 changes only the invoice identifier and returns "workspace": "B" with that invoice’s metadata. The known ownership, fixed actor and returned body support the finding within this example. A successful status code by itself would not establish the issue.
Restore the ownership check.
Cause in this example
The object lookup in this example does not enforce workspace ownership.
Recommended change
Enforce object ownership on the server before returning invoice data. Derive the workspace from the authenticated session and constrain the lookup to that workspace.
The example after-state returns the owned invoice normally and withholds the foreign object. Both paths matter: the fix should preserve legitimate access as it restores the boundary.
| Object requested | Before | Authored after-state |
|---|---|---|
/api/invoices/inv_A | E-01 · 200 Invoice metadata returned | R-01 · 200 Owned invoice remains accessible |
/api/invoices/inv_B | E-02 · 200 Invoice metadata returned | R-02 · 404 Empty body · no invoice data |
Request · Same workspace A member
GET /api/invoices/inv_A HTTP/1.1
Host: invoice.example.invalid
Cookie: [REDACTED]
Accept: application/jsonResponse · Authored after-state
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "inv_A",
"workspace": "A",
"total": 240
}Request · Same workspace A member
GET /api/invoices/inv_B HTTP/1.1
Host: invoice.example.invalid
Cookie: [REDACTED]
Accept: application/jsonResponse · Authored after-state
HTTP/1.1 404 Not Found
Content-Length: 0
Response body: empty (0 bytes).
The illustrated after-state satisfies these two checks. It is not evidence that a deployed fix passed, that a model performed a retest, or that the current product has closed this finding. A real closure decision requires a separately authorized retest against the actual changed target and its recorded evidence.
Keep the conclusion within the evidence.
This example covers one role, two fixture-owned objects and one endpoint. It does not establish application-wide coverage.
- The example does not assess other roles, write operations, payment routes, enumeration, session weaknesses or other application paths.
- No customer system, external target or live model was tested to produce this document. The inventory and all four exchanges are authored fixture content.
- The HTTP excerpts omit unrelated transport details. The credential placeholder is intentionally masked, and the invoice values are synthetic.
- Source implementation, a recorded observation, an independently confirmed result and an accepted deployment are separate evidence boundaries.
For a real handoff, carry the target and revision, authorization, selected identity, evidence references, responsible owner and acceptance criteria into the remediation record. Repeat the controlled comparison after the change and record what remains untested.