Skip to content

Repository files navigation

The Other User

The Other User: Alice creates a private invoice, then Bob uses a separate verified session to read the same invoice and exposes an authorization leak.

Your AI tested one user. Add another.

The Other User makes coding agents test authorization by changing the identity while keeping the resource and action fixed.

An open-source Agent Skill for Claude Code, OpenAI Codex, Cursor, and compatible AI coding agents.

CI GitHub release 16-case paired benchmark Open Agent Skills standard Listed on skills.sh MIT license

🌐 English · 简体中文 · Português · 日本語 · Español · Русский

If your app has accounts, private data, teams, tenants, sharing, or roles, this skill is for you.

Install · See the failure · Four rules · Benchmark · Read the skill

Authentication asks who are you? Authorization asks may this identity do this to that resource?

An AI agent can build a perfect one-user happy path and never ask the second question.

Alice creates it.  Alice reads it.  Alice updates it.  Tests pass.

That proves Alice's flow. It says nothing about Bob.

Alice created it. Make Bob try to read, change, delete, list, export, download, and subscribe to it.

Install in 30 seconds

Install for Claude Code, OpenAI Codex, Cursor, or another compatible agent:

The skill is listed on skills.sh:

npx skills add Pablo-aps/the-other-user

Then invoke it on an authorization boundary:

# Claude Code / Cursor
/the-other-user test whether a second account can read or update the first user's invoices

# OpenAI Codex
$the-other-user review this Supabase RLS policy with an owner and a different user

The skill can also activate when you ask an agent to test access control, object ownership, IDOR/BOLA, tenant isolation, roles, RLS, or cross-user access.

Manual install

Copy SKILL.md into a the-other-user skill directory:

Agent Project location Invoke
Claude Code .claude/skills/the-other-user/SKILL.md /the-other-user
OpenAI Codex .agents/skills/the-other-user/SKILL.md $the-other-user
Cursor .cursor/skills/the-other-user/SKILL.md or .agents/skills/the-other-user/SKILL.md /the-other-user

One happy path cannot test authorization

Without The Other User

Created invoice inv_42 as Alice.
Alice can list it, read it, and update it.
All tests pass. Authorization looks good.

With The Other User

VERDICT: LEAKS

Policy: only the invoice owner may read or update it.
Identity A: Alice — verified with /me
Identity B: Bob   — verified with a separate session

Alice creates inv_42                         -> 201
Bob lists invoices                           -> 200 []
Bob reads Alice's exact invoice inv_42       -> 200  LEAK
Bob updates Alice's exact invoice inv_42     -> 200  LEAK
Alice reads inv_42 after Bob's update        -> changed

The list was scoped. The object endpoint was not.
The database confirms Bob changed Alice's record.

The bug was not authentication. Bob was correctly logged in. The bug appeared only when a valid identity touched another identity's resource.

You probably need this if your AI is building…

Your app has… The second identity tests…
user-owned records another user reading, updating, or deleting the exact object
teams or workspaces a member, outsider, owner, and admin against the same resource
multi-tenant data the same local ID across two tenants, caches, queues, and exports
sharing or collaborators legitimate access stays allowed while unrelated access is denied
Supabase RLS owner, authenticated non-owner, anonymous, service role, and intended collaborators
REST or GraphQL APIs list vs direct object routes, nested resources, bulk actions, and alternate resolvers
files or media metadata, signed URLs, storage paths, and the downloaded bytes
realtime or background work subscriptions, events, workers, jobs, and persisted actor context
admin features client-hidden buttons vs server-enforced role checks

This is useful for vibe-coded SaaS, internal tools, marketplaces, fintech, healthcare, social apps, dashboards, and any product where one account should not silently become every account.

Four rules. One boundary.

01 — NAME 02 — SWAP
Name the actors, resource, action, and intended ALLOW, DENY, or UNKNOWN policy. Do not invent product policy from the implementation. Keep the exact resource and operation. Change the authenticated session, token, tenant, role, or database principal—and verify the identity really changed.
03 — CROSS 04 — VERDICT
Try every real door the resource already has: list, object, write, bulk, GraphQL, signed URL, export, realtime, cache, or worker. Check authoritative state after denied mutations. Return ISOLATED, LEAKS, NOT TESTED, or BLOCKED from evidence. Scope the claim; never say the whole app is secure.
same resource + same action + different verified actor = authorization test

Swap the identity, not merely the ID

This is not a second-user test:

Alice session + Alice's token + Bob written in a test variable

Neither is this:

Alice session + a different object ID

The skill requires separate sessions, cookie jars, tokens, database roles, or request contexts, plus an authoritative identity signal such as /me, token subject, server trace, or database principal.

Cross every real door

Authorization bugs hide in mismatched paths:

list is scoped             but GET /objects/:id is global
REST is protected          but GraphQL calls findById()
UI hides the button        but the API accepts the request
row read is protected      but signed URL minting is not
request is tenant-scoped   but cache key is only object_id
single delete is checked   but bulk delete skips per-item policy
API verifies the actor     but the worker trusts job.userId

A 403 is not the end of a write test. The skill verifies that the database row, file, event, job, or other authoritative effect did not change.

Keep the allowed controls

The goal is not to deny everyone. Public profiles should stay public. Collaborators should still collaborate. Admins should retain explicitly granted power.

Existing code is not automatically the policy; it may contain the bug. The skill derives expected access from requirements, permission tables, route contracts, RLS rules, or explicit direction. If the intended rule is genuinely unresolved, the correct verdict is BLOCKED, not a guessed security policy.

The verdicts

Verdict Meaning
ISOLATED Direct evidence covers the frozen actor × resource × action scope, including intended allowed controls, and observed access matches policy.
LEAKS A denied identity reads protected data, obtains a capability, changes authoritative state, triggers a protected effect, or crosses a tenant or role boundary.
NOT TESTED Only static code, mocks, one-user tests, incomplete logs, or unverified identity evidence are available. Risks remain risks—not observed leaks.
BLOCKED The required policy, approved second identity, environment, data, or access is unavailable, so safe verification cannot continue.

Every verdict stays narrow:

Verdict: ISOLATED | LEAKS | NOT TESTED | BLOCKED
Scope: <environment, resource, policy source>
Actors: <owner; second user / tenant / role>
Matrix: <actor × action × expected × observed × evidence>
Finding: <first contradiction or why proof is incomplete>
Authoritative effect: <state before and after denied mutations>
Residual risk: <untested relevant path and safest next proof>

Safety boundary

Use only systems and accounts you own or are explicitly authorized to test. Prefer local, test, or isolated staging fixtures. Never discover or probe real third-party user IDs, files, tenants, or tokens.

The skill does not grant permission to test a target. It does not turn your coding agent into a pentest framework. If a safe second identity or isolated environment is unavailable, it stops with BLOCKED rather than experimenting on production users.

Benchmark

In one reproducible paired snapshot, the same model reviewed the same 16 synthetic repository fixtures with and without the skill:

Metric Without skill With The Other User
Correct verdict 14 / 16 (87.5%) 16 / 16 (100%)
Correct NOT TESTED restraint 2 / 3 (66.7%) 3 / 3 (100%)
Correct BLOCKED restraint 1 / 2 (50%) 2 / 2 (100%)
Intended-access controls 4 / 4 4 / 4
Observed-leak cases 7 / 7 7 / 7
Decisive-signal recall 77.5% 86.3%
Decisive-evidence coverage 98.4% 97.9%

The interesting result is not that the skill shouted “leak” more often. Both arms found all seven observed leaks and preserved all four intended-access controls. The skill fixed two different confidence errors: baseline called a static risk an observed leak, and treated an unavailable second account as merely untested instead of an explicit blocking dependency.

The snapshot used gpt-5.6-luna at low reasoning through codex-cli 0.147.0, one run per cell, on August 19, 2026. Both arms received the same model, repository artifacts, neutral task prompt, and compact verdict schema. Treatment additionally received the committed skill and the separately recorded directive Use $the-other-user for this review.

Inspect the 32 raw outputs, 16 cases, output contract, and methodology. Recompute every hash and score locally:

node benchmark/check.mjs

This is one run per cell on synthetic, development-authored cases with a declared non-secret holdout. It is evidence that the skill changed this model's behavior on this fixture set—not an independent study, a security guarantee, a model ranking, or a stable estimate of future performance.

What this is not

The Other User is not:

  • a penetration-testing tool or permission to probe third-party systems;
  • an automated vulnerability scanner;
  • an authentication or authorization framework;
  • a replacement for threat modeling, code review, or domain-specific tests;
  • a claim that two accounts prove an entire application secure;
  • a reason to weaken legitimate public, shared, support, or administrator access.

It is one small behavioral skill:

Change the actor. Keep the resource. Test the boundary.

Frequently asked questions

What is The Other User?

The Other User is an open-source Agent Skill for authorization testing. It makes an AI coding agent repeat the same resource operation with a distinct, verified test identity and compare the result with the intended access policy.

Who should use it?

Anyone using Claude Code, OpenAI Codex, Cursor, or another coding agent to build an application with accounts, user-owned data, teams, tenants, sharing, roles, RLS, private files, exports, or realtime features.

Is this the same as authentication testing?

No. Authentication verifies identity. Authorization decides whether that identity may perform a specific action on a specific resource. A correctly authenticated Bob reading Alice's private record is an authorization failure.

Does a second user prove my app is secure?

No. A verdict covers only the tested actors, resources, actions, environment, and time. The skill is designed to expose a common missing dimension, not certify an application.

Does it work with Supabase RLS?

Yes. Use separate approved identities and test the exact row through the client path and, where appropriate, the database policy context. Include legitimate collaborator, anonymous, and service-role controls only when the intended policy grants them.

Will it test production users?

It should not. The safe boundary requires owned or explicitly authorized accounts and prefers local, test, or isolated staging fixtures. Without safe access, the verdict is BLOCKED.

Primary references

License

MIT © PABLO

About

Authorization testing for AI coding agents: change the identity, keep the resource, catch IDOR/BOLA, cross-user, role, and multi-tenant leaks.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages