Security Basics

9 min

Do AI Tools Introduce Vulnerabilities in Your App?

Do AI Tools Introduce Vulnerabilities in Your App?

AI doesn't make an app insecure by default. It removes the natural pauses where a developer would question an assumption. Where AI-assisted apps actually fail, and the five checks worth running before launch.

AI doesn't make an app insecure by default. It removes the natural pauses where a developer would question an assumption. Where AI-assisted apps actually fail, and the five checks worth running before launch.

A product can be live in a weekend and still carry security decisions nobody deliberately made. That is the uncomfortable answer to the question, do AI tools introduce vulnerabilities? They can - not because every AI-generated line is unsafe, but because AI speeds up implementation faster than most teams can verify the assumptions behind it.

For a founder, the risk is rarely an exotic zero-day. It is a Supabase service-role key shipped in a JavaScript bundle, row-level security turned off to make a query work, or an API route that accepts a user-supplied account ID without checking ownership. These are ordinary application flaws with immediate consequences: exposed customer data, unauthorised account access, fraudulent transactions, or a database bill that arrives after somebody has abused an open endpoint.

AI tools are useful. They can remove repetitive work, explain unfamiliar frameworks, and get a prototype into users' hands quickly. The trade-off is that generated code often looks credible before it has been tested in the context of your users, permissions, deployment settings, and third-party services.

Do AI tools introduce vulnerabilities by default?

No. An AI assistant does not automatically make an application insecure, just as a framework or code library does not. The issue is that AI produces plausible answers from incomplete context. It usually cannot see your production environment, your intended access model, or the full path from browser to database.

Ask an assistant to build a multi-tenant dashboard, for example, and it may generate a working query using a customer ID passed from the client. Unless the server verifies that the signed-in user belongs to that customer, the route may be vulnerable to insecure direct object reference, commonly called IDOR. Changing one value in a request could expose another company's records.

The same applies to authentication. A generated middleware snippet may check that a JWT exists but fail to validate its signature, expiry, audience, or issuer correctly. It may trust a role sent by the browser rather than retrieving permissions from a trusted source. The feature works in a demo. It is not necessarily safe when an attacker controls the request.

AI increases the chance of these gaps when teams treat generated code as finished code. It also makes it easier to assemble a large application from patterns that were never reviewed together.

Where AI-assisted applications commonly fail

Secrets are treated as configuration, not credentials

AI-generated setup instructions often place values in environment files and then suggest exposing selected variables to the frontend. That distinction matters. A public API key designed for browser use is different from a database password, payment secret, private signing key, or Supabase service-role key.

A service-role key bypasses row-level security. If it appears in a committed .env file, a client-side bundle, a public repository, or a deployment log, the issue is not cosmetic. An attacker may be able to read, alter, or delete data directly. Removing the key from the code is only part of the fix. It must be rotated, and access logs should be reviewed.

Access control is implemented in the interface

A common generated pattern hides an admin button for non-admin users and calls that access control. It is not. Anyone can construct the underlying request if the API endpoint does not enforce the same permission on the server.

This is particularly common in marketplace, booking, and SaaS products. A user may be prevented from seeing another user's invoice in the interface, yet still retrieve it by changing /api/invoices/123 to /api/invoices/124. Proper authorisation checks must happen at every sensitive server action and database query, not only in the browser.

For Supabase applications, row-level security is a major control point. Tables without RLS, policies that allow overly broad select access, and policies based on client-controlled fields can expose an entire tenant dataset. AI can draft policies, but a policy should be tested using real roles and deliberately hostile requests before it is trusted.

Payment logic accepts claims it should verify

Payment integrations are another place where working code can hide a serious weakness. A client application should not be able to declare that a payment succeeded, choose its own amount, or grant itself a subscription tier. Those decisions belong on the server and should be confirmed with the payment provider.

Webhook handlers need signature verification, replay protection where appropriate, and careful event handling. If an endpoint accepts a payment event without verifying its source, an attacker may be able to trigger order fulfilment or upgrade an account for free. If the code assumes webhook events arrive once and in order, normal provider retries can also create operational errors.

Dependencies and copied patterns bring baggage

AI assistants frequently recommend packages, boilerplate, and code fragments that were popular at some point. That does not mean they are maintained, compatible with your stack, or free of known vulnerabilities. A package may be safe in isolation but used unsafely in an application, such as a file upload library configured without type, size, or storage restrictions.

Generated regular expressions, SQL construction, redirect handlers, and HTML rendering are worth reviewing closely. The failure is often not a dramatic coding error. It is missing input validation, an unescaped value in an email template, or an open redirect added during an OAuth flow.

AI features create a separate attack surface

If your product sends customer content to an LLM, the application needs controls beyond standard web security. Prompt injection can cause a model to ignore instructions, disclose information included in its context, or call tools in an unintended way. The model should not be treated as an authorisation layer.

A support assistant with access to account data, for instance, must receive only the data the current user is entitled to see. If it can call internal tools, those tools need strict, server-side permission checks. Limit what each tool can do, validate arguments, and log sensitive actions. Never let model output directly execute database changes, send money, or alter user privileges without deterministic controls around it.

Why speed changes the security equation

The problem is not that founders move quickly. Speed is often the advantage that gets a product to market. The issue is that AI reduces the natural pauses where a developer might otherwise read documentation, question an implementation, or ask a security-minded colleague to review a sensitive change.

A small team may combine hosted authentication, a Supabase database, serverless functions, GitHub Actions, analytics, email delivery, and Stripe in a few days. Each service has sensible defaults and its own permission model. The weak points appear at the joins: a deployment variable exposed to the client, a webhook route excluded from middleware, an internal API left publicly reachable, or an RLS policy that no longer matches the application after a schema change.

Automated scanning finds part of this picture. It is useful for locating exposed secrets, vulnerable dependencies, insecure headers, and recognisable code patterns. It cannot reliably decide whether user A should be able to access user B's record, whether a role transition is valid, or whether a payment flow grants value before payment is confirmed. Those require manual review of the business logic and live application behaviour.

What to test before a fast-growing app becomes a target

Start with the areas where a single mistake has the broadest impact. A practical review should cover at least these five checks:

  • Search the repository, deployment configuration, and frontend assets for keys, tokens, passwords, service-role credentials, and private URLs.

  • Test every authenticated API route as a normal user, a different user, and an unauthenticated visitor to identify IDOR and missing authorisation checks.

  • Review database policies table by table. Confirm RLS is enabled where needed and that each policy enforces tenant and ownership boundaries.

  • Trace payment and subscription changes from the browser through server-side verification to webhook processing. The client should request an action, not decide its outcome.

  • Check production controls such as CSP, HSTS, secure cookie settings, CORS rules, rate limiting, error handling, and dependency versions.

Do not rely on a successful user journey as proof that these controls work. Test the negative cases: change identifiers, remove tokens, alter role values, replay requests, send unexpected webhook payloads, and try endpoints directly rather than through the interface. Attackers do not follow the happy path.

Treat generated code as an untrusted contribution

The most productive rule is simple: use AI to accelerate creation, then review its output with the same scepticism you would apply to code from an unfamiliar contractor. That does not mean manually inspecting every line with equal intensity. Prioritise boundaries: authentication, authorisation, secrets, payments, database access, file handling, and anything that accepts or returns customer data.

For a live product, an independent assessment is often faster than trying to infer risk from a growing codebase alone. HollowByte reviews the repository and deployed application together, combining automated checks with manual testing of the flaws AI-generated applications commonly miss, then provides severity-rated findings and exact remediation steps within 48 hours or less.

Your app does not need to be perfect before it earns users. It does need to make the right promises about who can access data, move money, and perform sensitive actions, and enforce those promises when someone deliberately tries to break them.

Back to blog

(function() { function applyMainRole() { var hero = document.getElementById('hero'); if (!hero) return false; var node = hero; while (node.parentElement && node.parentElement !== document.body) { node = node.parentElement; } if (node && node.parentElement === document.body) { node.setAttribute('role', 'main'); return true; } return false; } if (applyMainRole()) return; var attempts = 0; var interval = setInterval(function() { attempts++; if (applyMainRole() || attempts > 20) { clearInterval(interval); } }, 250); })();