All posts

Field guide

How to secure an AI-built API in an afternoon

An API generated by an assistant works on the happy path and quietly skips the guards that make it safe. The good news is that the gaps are predictable, so you can close most of them in a focused afternoon. Here is the checklist, in the order that removes the most risk first.

Last updated

An AI-built API tends to fail in the same handful of ways, because the assistant optimizes for endpoints that respond correctly, not endpoints that hold up under a hostile caller. That predictability is what makes this quick: you are not auditing everything, you are walking a short list of known gaps. Work it in this order and you remove the most risk first.

1. Authorization on every data endpoint

The biggest and most common gap. For each route that reads or changes data by an id, confirm the server checks that the record belongs to the current user, not just that the user is logged in. A check in the UI does not count, because anyone can call the route directly. This is broken access control, and it is where to spend your first hour. Fix pattern: a missing authorization check.

Want to see exactly what Prbl flags? Watch it scan a demo app, no repo or account needed.

See a live scan →

2. Input handling on every query and command

Find any place user input reaches a database query, a shell command, or a parser, and make sure it is passed as data, not concatenated into the instruction. Parameterized queries for SQL, argument arrays for shell commands, and safe loaders for deserialization.

3. Rate limits on auth and expensive routes

Put a limit on login, password reset, and anything that sends a code or calls a paid service, so volume alone cannot brute-force a password or run up your bill. Key the limit on the real client IP. The rate-limiting walkthrough covers the details.

4. Secrets out of the code

Confirm no API key, token, or connection string is a literal value in the source, and that no .env is committed. Read secrets from environment variables, and rotate anything that was ever hardcoded. The four-layer secrets setup makes this stick going forward.

5. No insecure defaults, no leaked internals

Check that nothing disables a protection to make things work, no TLS verification off, no CORS wildcard with credentials, no cookies missing their flags, and that error responses return a generic message rather than a stack trace. These are the insecure defaults assistants ship, and each is a one-line fix.

Test the unhappy path

For each fix, prove the disallowed path is now closed, not just that the allowed one still works. Call an endpoint with another user's id and confirm you get nothing. Exceed a rate limit and confirm you are rejected. Send special characters and confirm they are treated as data. The allowed path already worked; the point is to verify the attack no longer does.

Frequently asked questions

Where should I start if I only have an hour?

Start with authorization on your data endpoints. It is the most common serious gap and the easiest to exploit, since anyone can call a route directly and change an id. Go through every endpoint that reads or changes data and confirm it checks, on the server, that the record belongs to the current user. If you fix nothing else in the first hour, fix that.

My API uses a bearer token, not cookies. Does that change anything?

It changes some things and not others. Bearer-token APIs are not vulnerable to CSRF the way cookie-authenticated ones are, so that item drops off. Everything else stays: authorization checks, input handling, rate limiting, keeping secrets out of code, and not leaking internal details in errors. Match the checklist to how your API authenticates, but do not assume a token removes the need for per-request authorization.

How do I test that the fixes actually work?

Test the disallowed path, not just the allowed one. For authorization, call an endpoint as one user with another user's id and confirm you get nothing. For rate limiting, send more requests than the limit and confirm you get rejected. For input handling, send a value with special characters and confirm it is treated as data. The allowed path already works; you are proving the unhappy path is closed.

Is a checklist enough, or do I still need a scan?

The checklist is for the endpoints you remember to look at; a scan covers the ones you forget and the patterns that are easy to miss by eye. Use the checklist to fix intent-level issues you understand, like which routes need ownership checks, and use a scan to catch the mechanical patterns, like a hardcoded key or a concatenated query, across the whole codebase. They cover different gaps.

Cover what the checklist misses

The checklist handles the endpoints you look at; a scan catches the ones you forget and the patterns that are easy to miss by eye, across the whole codebase, with the file and line for each. Run it at the start to find the gaps and at the end to confirm they are closed. Run a free scan on your API and work down the list.

Prbl scans your live app or your codebase for exactly the kinds of issues above.

How to Secure an AI-Built API in an Afternoon: Prbl