Security Basics
6 min
A working payment integration, a Supabase client initialised in minutes, and a polished login flow can make a new SaaS feel ready to ship. But can AI code leak secrets? Yes. It can copy a credential into a browser bundle, suggest an unsafe environment-variable pattern, or leave a real token in a test file that reaches your repository.
The problem is not that an AI coding assistant is deliberately trying to expose your data. It is that it generates plausible code from patterns, incomplete context and prompts that may contain sensitive material. It cannot reliably tell which value is safe to publish, which key bypasses database controls, or whether a code snippet will later be bundled into a public frontend.
For a founder, the operational risk is straightforward: a secret that reaches a public repository, deployed JavaScript file, error log or exposed endpoint may be copied by anyone. The result can range from an unexpected cloud bill to database deletion, account takeover, fraudulent payments or a reportable data exposure.
Can AI code leak secrets in a live application?
Yes, and the most damaging leaks are often introduced after the initial prompt. An AI assistant may provide a placeholder such as SUPABASE_SERVICE_ROLE_KEY, a Stripe restricted key or a JWT signing secret. A developer under launch pressure pastes in the real value to make the example work, then places it in the wrong file or commits it before adding the correct ignore rule.
Once code is deployed, a client-side environment variable is not private merely because it has a reassuring name. In frontend frameworks, variables explicitly exposed to the browser are compiled into JavaScript that visitors can download. A secret in a NEXT_PUBLIC_, VITE_, REACT_APP_ or similar variable should be treated as public. Renaming a privileged key does not change that.
This is especially serious for Supabase projects. The anon key is designed for use in a client application, provided row-level security, or RLS, is configured correctly. The service-role key is different: it bypasses RLS. If an AI-generated setup puts that key in a frontend configuration file, an attacker may be able to read, modify or delete data directly through the API.
The same distinction applies across your stack. A browser-safe publishable payment key is not equivalent to a payment secret key. A public analytics identifier is not equivalent to an API token with write access. AI-generated code can make these values look interchangeable because both are strings in a configuration file. Your permissions model says otherwise.
Where secrets commonly end up
Secrets do not need to appear in an obvious file called secrets.txt to cause trouble. During an audit, the usual findings are scattered across code, configuration and deployment history.
A common source is the committed .env file. The application works locally, so the file is added during an early commit. It is later removed, but the key remains available in Git history. Deleting the current line does not revoke a credential or erase earlier commits from every clone, fork, build log and backup.
Another is a frontend bundle. A developer follows an AI suggestion to initialise a server-side SDK in a React component, or exposes a server variable so the build stops failing. The deployed site now contains the credential in a JavaScript asset. Attackers do not need to break into your hosting account to retrieve it.
Generated scripts and test fixtures are also easy to overlook. Seed scripts may include an admin password, a database connection string or a service account token. A debug.ts, migration.js or copied cURL command may carry a live bearer token. These files are often outside the main product path, so they receive less review just when they need more.
Finally, logs can become a secondary leak. AI-generated error handling may print request headers, authentication objects or full provider responses to a console. If those logs are retained by a hosting platform, viewed by contractors or exposed through an overly helpful debug endpoint, tokens can spread beyond the original application.
A leaked key is only the first failure
A credential’s impact depends on what it can do. That is why finding a key is not enough: you need to trace its privileges, its exposure and the controls around it.
Consider a leaked database URL. If the database accepts connections from the internet and the credential has broad privileges, the attacker may have direct access. If the same value is limited to a private network and a low-privilege role, the immediate impact is smaller. It still needs rotation, but the incident path is different.
Or consider an exposed Supabase anon key. By itself, this is not necessarily a vulnerability. The real question is whether RLS policies enforce that a signed-in user can access only the rows they should see. If RLS is disabled, policies are missing, or a policy trusts user-controlled fields, the public API key becomes a route into every customer record.
Authentication code needs the same scrutiny. An AI assistant may scaffold a JWT check that verifies the token format but not its signature, issuer, audience or expiry. It may put an authorisation decision in the browser rather than on the API. It may expose an IDOR flaw by fetching /api/orders/:id without confirming that the requesting user owns that order. None of those weaknesses requires a leaked secret, but a leaked token can make exploiting them easier.
Why AI-assisted teams miss the warning signs
Speed changes review habits. When a feature is generated, adapted and deployed in a few hours, the team may test whether it works without asking where authority lives. The code can look conventional, pass a basic happy-path test and still expose a privileged credential or skip a server-side permission check.
AI also tends to offer generic implementation patterns. Generic patterns are useful starting points, but they cannot account for your actual environment: which variables your platform exposes at build time, whether a token is production-grade, which database tables contain sensitive information, or whether your payment provider’s webhooks are verified.
There is a trade-off here. Moving quickly with AI assistance is sensible for a small team. Treating generated integration code as reviewed security code is not. The highest-risk areas deserve a deliberate check before release: authentication, authorisation, database access, file uploads, payment flows, admin routes and every environment variable that grants access.
What to do if you find an exposed secret
Do not start by simply hiding the value in the latest commit. Assume the secret is compromised if it has reached a public repository, browser bundle, shared log, production error response or an unknown third party.
First, revoke or rotate it. Create a replacement credential, update the server-side deployment configuration, and verify that the old value no longer works. For database and service credentials, review access logs where available. Look for unfamiliar requests, changes to permissions, unexpected data exports, new users or altered payment settings.
Next, remove the source of exposure. Move privileged operations behind a server-side endpoint, keep server credentials in your host’s secret manager, and ensure client code only receives values intentionally designed to be public. If the value was committed, remove it from the working tree and assess repository history, but do not rely on history rewriting as the security fix. Rotation is the fix.
Then check adjacent controls. A leaked service-role key demands an RLS review. A leaked payment credential demands a review of refunds, webhooks and account permissions. A leaked JWT secret demands token invalidation and verification of every service that accepts those tokens. The aim is to close the full misuse path, not just remove one string.
Build a release check that suits your team
You do not need a large security department to catch the majority of preventable leaks. You need a release process that treats secrets and access control as deployment blockers.
Before shipping, scan the repository and commit history with a secrets scanner such as GitLeaks. Use dependency scanning to identify vulnerable packages, static analysis to flag dangerous code patterns, and a live application scan to identify exposed endpoints and missing headers. Automated checks are valuable because they are repeatable, but they cannot decide whether a particular Supabase policy lets one customer read another customer’s invoices.
That is where manual review matters. Inspect files that initialise SDKs, API routes that use admin credentials, deployment variables, authentication middleware and database policies. Confirm that every sensitive operation is enforced on the server, not merely hidden in the interface. Check that CSP, HSTS and other security headers support the way your application actually runs rather than breaking it after launch.
For founders without spare engineering time, HollowByte combines automated scanning with manual review of AI-built application paths, then prioritises exact fixes by severity. The useful output is not a vague warning that security should improve. It is a finding tied to a file path, endpoint or configuration, with the exposure explained and the corrective action defined.
Your application does not need to be perfect before it can grow. It does need to know which keys are public, which identities can access which data, and whether the generated code enforcing those rules is doing what you think it is. Check that before the next feature release, while a rotation is routine rather than an incident.
Back to blog
