AI-written endpoints often confirm that a request comes from a logged in user without checking that this user may touch this specific record. In review, look at every handler that takes an identifier and ask where ownership or role is checked. Then write a test that uses the wrong user.
Authentication is not authorization
Authentication answers who you are. Authorization answers what you may do. An assistant asked to "add an endpoint to fetch an invoice" will usually add the login check from the surrounding code and then fetch by the identifier in the URL. Nothing asks whether the invoice belongs to the caller.
The result is the classic pattern where changing a number in the URL returns someone else's data.
Where it hides
- Handlers that take an id in the path or body.
- Update and delete operations, which are often less carefully checked than reads.
- Bulk and export endpoints that skip the per record check.
- Background jobs and webhooks acting on behalf of users.
- New routes added beside well protected ones, where middleware was not applied.
A review routine
- List every new route in the pull request.
- For each, find the line that checks role or ownership. If you cannot find it in under a minute, flag it.
- Check that the check happens on the server, not only in the interface.
- Confirm the query itself is scoped, for example by filtering on the owner in the database call.
- Look for the default: a new route should deny until someone grants access.
Tests that expose it
Create two users. User A creates a record. User B, logged in, requests it, updates it and deletes it. All three must be refused. Add one test for an unauthenticated caller. See tests to demand before merging AI-written code.
Instruct the assistant, then verify
Telling the assistant in its rules file that every route needs an explicit authorization check reduces misses. It does not remove them, so keep the review and the tests.
Where tooling helps
Static analysis catches some missing checks, and dynamic testing against a running app catches more because it behaves like a user. Safeguard's scanning capabilities include API and web target scans that can help here.
Fixing it centrally
Where possible, move the check out of each handler. A shared policy layer, or a query helper that always filters by the current user, means a new route is protected by default and a missing line becomes a failing test instead of a data leak. Ask the assistant to use the helper, and flag any handler that bypasses it.
Quick check
Does a framework's built in login middleware solve this?
It covers authentication. Object level authorization still needs code that compares the caller with the record or role requirement.
Last reviewed: 19 October 2026.