[Agent Tools](https://tools.openkrill.app/) / [Blog](https://tools.openkrill.app/blog)

# The backend readiness checklist, explained with what an outside check can see

An app built fast with AI can look finished while its backend is not. Of the 16 items on our checklist, an outside request can see 5, and one of those only in part. The other 11, plus the inside half of that one, live in your code and your database, so only you can check them.

By OpenKrill. Published 2026-10-08. The short list is on the [backend readiness checklist page](https://tools.openkrill.app/backend-checklist); this post explains each item and the evidence behind it.

## The short answer

A scanner that only sends requests from outside cannot tell you if your passwords are hashed, if one user can read another user's orders, or if your backups restore. It can tell you if your API answers 500 to a bad query, if an error page prints a stack trace, if CORS echoes any origin, and if you have a health check. That split is the whole point of this post: know which half a tool can cover, and do the other half yourself.

| Group | Items | Who can check |
| --- | --- | --- |
| Read from outside | Validate all input, Rate limit on login and reset, Health check that verifies the database, CORS locked down | Site Check, in one call |
| Read in part | Logs with a request id and no tokens | Site Check reads error pages; the log itself is yours |
| Only you | The other 11 items, below | You, with the check we give for each |

## Why this list matters more for AI-built apps

Code assistants write code that runs, and running code is not the same as safe code. In 2021, a study of GitHub Copilot found that about 40% of 1,689 programs it wrote for 89 risky scenarios had a vulnerability ([Pearce and others, 2021](https://arxiv.org/abs/2108.09293)). A user study a year later found that people who used an AI assistant wrote less secure code and were more confident that it was secure ([Perry and others, 2022](https://arxiv.org/abs/2211.03622)).

The newer numbers are about whole apps. A 2026 audit of 200 vibe-coded apps found at least one vulnerability in 91.0% of them, and 65.77% of the flaws were rated Critical or High, mostly broken access control, injection and authentication ([Deng, Fan and Meng, 2026](https://arxiv.org/abs/2606.23130)). A benchmark of agent-written code found SWE-Agent with Claude 4 Sonnet solved 57% of real tasks correctly but only 11.8% securely ([Zhao and others, 2025](https://arxiv.org/abs/2512.03262)). In both, the gap is the backend: the parts a demo never shows.

## The 5 items an outside request can see

These are the checks Site Check runs in its `exposure_check` tool, on a host you have proved you own. Each one is plain GET requests, never a sign-in and never a load test. The results below are from our own run on tools.openkrill.app at 03:55 UTC on 2026-10-08, which made 34 requests in total.

- **Validate all input.** One request with a broken query string and one to a path that does not exist. A 500 means your code trusted input it should have rejected. Our site answered 200 and 404, a pass. The OWASP rule is to parse safely and then validate, with size limits on every request ([OWASP Input Validation Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html)).
- **Rate limit on login and reset.** One plain GET of the sign-in or reset page your page links to, looking for rate-limit headers. Our tool site has no sign-in, so this came back as not checked, which is the honest answer. A limited client should get 429 Too Many Requests, with Retry-After if you can ([RFC 6585, section 4](https://datatracker.ietf.org/doc/html/rfc6585)).
- **Logs with a request id and no tokens, in part.** The error pages already fetched are read for stack traces, tokens and keys. Our run read 1 error page and found neither. Whether your real logs carry a request id and keep out session ids, access tokens and passwords is yours to read ([OWASP Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html)).
- **Health check that verifies the database.** GET /health, /healthz and /api/health. Our static site has none, so the tool marked it as needs verification instead of a failure. For an app with a database, the check should touch the database, or it will say "ok" while every real request fails.
- **CORS locked down.** One GET with a made-up Origin header. An echoed origin or a wildcard is reported. Our page sent no Access-Control-Allow-Origin to another site, a pass. Note that browsers refuse a credentialed request when the server answers with the `*` wildcard, so a wildcard plus cookies does not even work ([MDN, CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS)).

## The 11 items only you can check

Each item below has a reason, a check you can run in a few minutes, and the primary source we rely on.

### Access

- **Server-side auth on every route.** Hiding a button does not stop a direct API call. Sign out, call one private route with curl and no cookie, and expect 401 or 403.
- **One user cannot read another user's data.** This is the top API risk on the OWASP list: every endpoint that takes an object id needs its own ownership check ([OWASP API1:2023](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/)). Sign in as test user A, request an object of test user B by its id, and expect 403 or 404.

### Secrets and passwords

- **Hashed passwords.** Use Argon2id with at least 19 MiB of memory, 2 iterations and parallelism 1, and scrypt where Argon2id is not available ([OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)). Look at one row of your users table: the hash names its algorithm at the start.
- **Secrets outside the repo.** OWASP notes that many teams still keep keys hardcoded in source and config files in plain text ([OWASP Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html)). Run gitleaks or trufflehog over the whole git history, not only the current files, and rotate what it finds.

### Load and failure

- **Timeouts on external calls.** One slow provider can hold every request open. Missing timeouts and limits are how one caller exhausts an API ([OWASP API4:2023](https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/)). Find each fetch or SDK call to another service and confirm a timeout of a few seconds.
- **429 not 500 when saturated.** Turning a request away still costs the server work, so it must be cheap and early ([Google SRE book, Handling Overload](https://sre.google/sre-book/handling-overload/)). On a staging copy, send more requests than your limit with k6 or oha and expect 429, not 500.

### Data that stays correct

- **Idempotent payments.** A retry or a double click must not charge twice. An idempotency key lets a client retry a write safely ([Stripe, idempotent requests](https://docs.stripe.com/api/idempotent_requests)). Replay one webhook event twice in test mode; the order must change once.
- **Transactions for multi-step writes.** A crash between two writes leaves half an order. Every handler that writes to more than one table should run inside one transaction or batch.
- **Indexes on the columns you query.** A query that is fast on 100 rows times out on 100,000. Run EXPLAIN on your top queries and index any full scan on a filter or join column.
- **Versioned migrations.** Every schema change should be a numbered file in the repo, applied by a tool, so it can be repeated and rolled back.

### Recovery

- **Backups with a tested restore.** A backup you have never restored is a guess. Once a quarter, restore last night's backup into a fresh database, open the app against it and write down how long it took.

## How to run the outside half

Open [Site Check](https://tools.openkrill.app/site-check) and ask your agent to call `exposure_check` on your host, or add the server in [Claude](https://tools.openkrill.app/integrations/site-check/claude), [ChatGPT](https://tools.openkrill.app/integrations/site-check/chatgpt), [Cursor](https://tools.openkrill.app/integrations/site-check/cursor) or [Pi](https://tools.openkrill.app/integrations/site-check/pi). The first call asks you to publish a short token, so it only reads hosts you own. The answer lists the 5 outside items with a status each, and then the 12 owner items as a list for you, never as a pass. We ran it on our own site and wrote up the result in [We ran Site Check on our own tool site](https://tools.openkrill.app/blog/site-check-on-our-own-site).

**Try it:** Site Check reads the outside half of this list for a host you own in one call. [Open Site Check](https://tools.openkrill.app/site-check).

## Where the list comes from

The 16 item names follow a post on X by [@precisox](https://x.com/precisox) about what a vibe-coded backend often skips. The explanations, the checks and the split between outside and owner items are ours.

## Sources

- [Pearce, Ahmad, Tan, Dolan-Gavitt, Karri. Asleep at the Keyboard? (2021)](https://arxiv.org/abs/2108.09293): about 40% of 1,689 Copilot programs in 89 risky scenarios were vulnerable.
- [Perry, Srivastava, Kumar, Boneh. Do Users Write More Insecure Code with AI Assistants? (2022)](https://arxiv.org/abs/2211.03622): AI users wrote less secure code and felt more sure of it.
- [Deng, Fan, Meng. Understanding the (In)Security of Vibe-Coded Applications (2026)](https://arxiv.org/abs/2606.23130): 91.0% of 200 audited vibe-coded apps had at least one vulnerability.
- [Zhao, Wang, Zhang, Luo, Li, Li. Is Vibe Coding Safe? (2025)](https://arxiv.org/abs/2512.03262): 57% of tasks solved correctly, 11.8% securely.
- [OWASP API1:2023 Broken Object Level Authorization](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/): every endpoint that takes an object id needs an ownership check.
- [OWASP API4:2023 Unrestricted Resource Consumption](https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/): missing timeouts and limits let one caller exhaust an API.
- [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html): Argon2id with at least 19 MiB, 2 iterations and parallelism 1, else scrypt.
- [OWASP Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html): many teams keep secrets hardcoded in source and config.
- [OWASP Input Validation Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html): parse safely, then validate, with request size limits.
- [OWASP Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html): keep session ids, access tokens and passwords out of logs.
- [Nottingham, Fielding. RFC 6585 (2012)](https://datatracker.ietf.org/doc/html/rfc6585): 429 Too Many Requests, with an optional Retry-After.
- [MDN, Cross-Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS): credentialed requests cannot use the wildcard origin.
- [Google SRE book, chapter 21, Handling Overload (2016)](https://sre.google/sre-book/handling-overload/): rejecting a request still costs resources.
- [Stripe API reference, Idempotent requests](https://docs.stripe.com/api/idempotent_requests): an idempotency key makes a retried write safe.
- Our own run: Site Check `exposure_check` on tools.openkrill.app, 2026-10-08 03:55 UTC, 34 requests, verdict clean.
