Bespoke Software  /  The Risks You Can't See

The risks you can't see

AI writes code that runs, demos cleanly, and passes the security scan. The dangerous flaws are the ones a scan was never shaped to catch. Here are the prompts we use to go looking for them — and why a clean report still isn't a correct system.

What this means for a business owner. AI can produce software that appears to work while still containing logic or security problems that are hard to spot. The point of independent review is not to slow development down; it is to make sure "working" also means safe, correct and maintainable. The technical detail below is for anyone who wants to see how that review is done.

A four-step adversarial pass, plus a test plan

On our Vibe Coding page we describe building an application with one AI model, then reviewing it with another — and the second model finding 24 serious issues in code that worked and passed its own tests. These prompts are part of how that review gets done: turn the model against its own output, map where attacks get in, try to break it, make it distrust its first answer, then prove the fixes hold. Run them in order — each builds on the last.

security-scan · transfer.js
post('/api/transfer', (req, res) => { const amount = req.body.amount const from = session.userId const to = req.body.to db.transfer(from, to, amount) // ship it })
SQL injection — none
XSS — none
Auth present — yes
Secrets in code — none
Dependencies — current
Scan complete — 0 vulnerabilities found
No check for: amount = -500 — funds flow the wrong way and drain the recipient.The code is secure. It is not correct.
Every box ticked. The hole is in the logic — exactly where an automated pass has nothing to say.

These are deliberately distilled from the longer versions we use when reviewing our own builds and AI-assisted software.

They're enough to run a genuinely useful pass on your own code — and enough to show you the shape of the technique. The judgement of which findings to trust, what the model quietly skipped, and what to actually do about it is the part that doesn't fit on a web page.

Five prompts, copy-ready

01

Map the attack surface

Find every way data gets into the system, and where it ends up.

Act as a hostile security reviewer who has just been handed this codebase with no prior context. Before assessing any vulnerabilities, map the attack surface: list every point where untrusted data enters the system — HTTP endpoints, query/path/header params, request bodies, file uploads, websocket messages, environment variables, third-party API responses, deserialised data. For each entry point, trace where that data flows and what it eventually touches: database, filesystem, shell, template renderer, another service. Output a table of entry point → sink. Do not suggest fixes yet. Flag anything where you can't determine the destination — unknown flows are where I want to concentrate.
02

Try to break it

Attack each route for real — concrete exploits, not a generic checklist.

For each entry-point-to-sink flow you identified, act as an attacker trying to break it. For every flow, construct a concrete exploit: the specific malicious input, what it would do, and the line(s) that make it possible. Cover at minimum injection (SQL, command, template, LDAP), broken access control (can I reach this without authorisation, or reach another user's resource by changing an ID?), authentication and session weaknesses, SSRF, path traversal, insecure deserialisation, and secrets or sensitive data exposed in code, logs or responses. For each finding give me severity, the exact payload, and the precise location. If you cannot build a working exploit for a suspected issue, say so explicitly — I want real findings, not a checklist of theoretical worries.
03

Attack your own answer

Make the model distrust its first pass and re-test its own assumptions.

Now review your own previous analysis as a sceptical second auditor whose job is to catch what the first reviewer missed. What did you assume was safe without checking? Which framework or library defaults did you trust that might not actually be enabled or configured? Did you check the auth logic itself, or only assume it works? Did you look at error-handling and failure paths, where security controls commonly get bypassed? Did you consider what happens when two requests race? List every assumption your first pass made, then test the three most dangerous ones. The goal is to break your own earlier conclusions.
04

Triage and fix

Rank by real risk, fix the worst, and be honest about what needs a human.

Consolidate everything into a prioritised remediation plan. Rank findings by real-world risk — likelihood of exploitation × blast radius if exploited — not raw CVSS. For the top items, give me the specific code fix with before/after, and name the root-cause pattern so I can find other instances of the same mistake elsewhere. Separately, flag anything that needs a human security professional rather than a generated fix: auth architecture, cryptography choices, anything where a wrong fix creates false confidence. Be explicit about what this review cannot catch — business-logic flaws specific to my domain, vulnerabilities in dependencies, and anything requiring runtime or infrastructure context you can't see from the code.
05

Prove it with tests

Write tests that prove each hole is closed and nothing else broke.

From the vulnerabilities and flows you've identified, write a test plan that proves each fix works and stays fixed. For every finding, give me a test that confirms the exploit is now blocked (the malicious input fails safely) and a test that confirms legitimate input still works (so the fix didn't break the feature). Cover the boundaries — empty, oversized, malformed, wrong-type and edge-case inputs — and the auth matrix: each protected action tried as the right user, the wrong user, and no user. Mark which tests can be automated in my existing framework versus which need manual verification, and flag any flow you can't test without runtime or infrastructure I haven't shown you.

Secure isn't the same as correct

A model can confirm there's no SQL injection on your funds-transfer endpoint and have no idea the endpoint happily accepts a negative amount.

The code runs. The demo works. The scan is clean. And the bug is invisible until someone finds it — because the most dangerous flaws in AI-assisted code rarely sit where a security pass is shaped to look. They live in the gap between secure and correct, and that gap is domain knowledge no model has about your business.

These prompts close a lot of the mechanical, pattern-shaped risk. Closing the rest is judgement — knowing your business well enough to spot the bug the machine had no reason to look for. Confidence isn't correctness.

Want a second pair of eyes on it?

If AI-assisted code is finding its way into your business, our Check My Code review does this properly — security, fragile logic and the hidden problems experience catches, before a customer does. The first conversation is free, and there's no sales pitch.

01684 899403