Security Basics

7 min

How a Security Audit for AI Generated Code Works

How a Security Audit for AI Generated Code Works

What a real security audit actually examines in an AI-built application, from exposed credentials and broken RLS policies to payment logic that trusts the browser instead of the server.

What a real security audit actually examines in an AI-built application, from exposed credentials and broken RLS policies to payment logic that trusts the browser instead of the server.

A security audit for AI generated code is not a checkbox after launch. It is the work that tells you whether a customer can read another customer’s records, whether a service-role key is sitting in a public bundle, or whether a payment endpoint can be called without the checks your business depends on.

AI-assisted development has made it possible to ship useful products at remarkable speed. It can also produce code that looks plausible, passes a happy-path test and still fails at the boundary where a hostile user starts changing IDs, replaying requests or inspecting browser assets. The risk is rarely that every line is wrong. The risk is a small, ordinary-looking omission in the code or configuration around it.

For founders, that distinction matters. You do not need a lecture about every security standard. You need to know what is exposed, how serious it is, what could happen if it is abused and the exact fix required.


Why AI built applications need a different review

AI tools are good at assembling familiar patterns: a login flow, a Supabase query, a Stripe webhook handler or an API route. They are less reliable at understanding the rules unique to your product. Those rules are where application security lives.

For example, an AI-generated prompt may create an endpoint that accepts a userId from the browser and fetches that user’s account data. The endpoint works in testing. But if it does not verify that the signed-in user is entitled to request that ID, any authenticated customer may be able to enumerate other accounts. That is an insecure direct object reference, usually shortened to IDOR. It is a straightforward flaw with serious consequences.

The same pattern appears in database policies. A generated application can connect successfully to Supabase while row-level security is disabled, incomplete or written around a client-supplied identifier. A developer sees records loading correctly and moves on. An attacker sees a database they may be able to query, alter or delete.

This does not mean AI-written code is inherently unsafe, or that hand-written code is safe. It means fast assembly changes the review requirement. The code needs to be tested against real abuse cases, not only the intended product flow.


What a security audit for AI generated code should examine

A useful audit reviews both the live application and the repository. Looking at only one creates blind spots. The live app shows what is actually exposed to the internet. The repository shows the logic, secrets, dependencies and configuration that may explain the exposure.


Credentials and client-side exposure

Start with secrets. Public frontend bundles, repositories, environment files, build logs and old commits can contain API keys, database URLs, tokens and third-party credentials. Some keys are designed to be public, but their presence still needs context. A Supabase anonymous key with correctly enforced RLS is different from a service-role key included in a JavaScript bundle.

The audit should identify the key, where it appears and what it can do. “Secret detected” is not enough. A founder needs to know whether it can access production data, send transactional messages, create payment actions or be safely rotated as a precaution.

Authentication and authorisation

Authentication answers who the user is. Authorisation answers what they can do. AI-generated applications frequently handle the first part adequately and leave gaps in the second.

Reviewers should test protected pages, API routes and server actions with altered identifiers, missing tokens, expired tokens and accounts with different roles. They should check how JWT claims are validated, whether privileged actions are controlled server-side and whether a user can change their own role, organisation or subscription status through a crafted request.

A common failure is trusting data from the browser because the interface hides an option. Hiding an admin button is not access control. The server must reject the request even when it is made directly.

Database access and Supabase RLS

For teams using Supabase, row-level security deserves focused review. RLS can provide strong tenant isolation, but only when it is enabled on the relevant tables and policies match the product’s actual ownership model.

An audit should inspect which tables have RLS enabled, which roles can access them and whether policies use authenticated identity rather than a value supplied in the request. Storage buckets, RPC functions and database views need the same attention. A secure table policy does not help if a broadly permissive view or function bypasses the intended control.

The practical test is simple: can one normal user access another user’s data by changing an ID, a filter or an organisation value? If the answer is yes, the issue should be treated as a high-priority fix, not a future hardening task.


APIs, payments and business logic

Security flaws are not limited to data theft. In a marketplace, SaaS product or paid tool, an unsafe payment flow can become fraud or direct revenue loss.

Review payment endpoints for client-controlled prices, quantities, product IDs, coupon values and entitlement updates. A checkout session should be created from trusted server-side product data, not from an amount posted by the browser. Webhook handlers should verify signatures and handle replay safely. Subscription status should come from a verified payment event, not a success page the customer can visit directly.

Business logic deserves the same scepticism. Can someone claim a referral reward repeatedly? Can they create unlimited trial accounts? Can they submit a request intended for an internal operator? These are product-specific questions, which is why a purely automated scan is useful but insufficient.


Dependencies and browser defences

A sound review also checks third-party packages for known vulnerabilities and identifies packages that are abandoned, unnecessary or risky in their current version. A vulnerable dependency is not always immediately exploitable, but it should be assessed in the context of how your application uses it.

Security headers are another low-effort, high-value area. Missing Content Security Policy, HSTS, frame protections or restrictive cookie settings can increase the impact of other mistakes. Headers will not repair broken authorisation, but they reduce avoidable exposure and should be configured deliberately.


Automated scanning finds clues. Manual testing proves impact.

Tools such as GitLeaks, Snyk, Semgrep, OWASP ZAP and Burp Suite are valuable because they search quickly and consistently. They can flag leaked secrets, unsafe code patterns, outdated dependencies and common web weaknesses across a codebase and live environment.

They cannot reliably determine whether your organisation boundary is correct, whether a generated RLS policy protects the right records or whether a payment action can be manipulated for your exact product model. That requires a reviewer to read the implementation, follow the requests and attempt the misuse an attacker would try.

There is a trade-off here. An automated report can be fast and broad, but it often creates noise and leaves the hardest question unanswered: what should be fixed first? Manual review takes expertise, but it converts raw findings into a severity-rated plan tied to business impact.


What an actionable audit deliverable looks like

A report should not leave your team translating vague findings into engineering work. Each issue should state its severity, affected URL or file path, the evidence observed, the likely business impact and a specific remediation approach.

For a critical exposed service-role key, that may mean immediately revoking and rotating the credential, removing it from the client bundle, moving the operation to a protected server-side route and reviewing logs for use. For an IDOR issue, it may mean enforcing ownership checks in the API handler and adding a database-level RLS policy so one missed route cannot reopen the problem.

Priority matters. Fix public data access, account takeover paths and payment abuse before cosmetic header improvements. Then retest the changes. A remediation is only complete when the original attack path no longer works.


A practical route from launch to confidence

The fastest useful process is usually three steps. Provide access to the live application and repository, allow automated and manual analysis, then work through a plain-English report with clear fixes. If internal capacity is limited, remediation support can prevent urgent findings from sitting in a backlog while the product keeps growing.

HollowByte applies this approach to live, AI-built applications, with findings prioritised for founders who need to make decisions quickly rather than decode a generic scanner export.

Your application does not need to be perfect before it is reviewed. It needs an honest assessment before a small gap becomes a customer incident, a fraud problem or a difficult conversation you could have avoided.

Back to blog