AI-generated app security is becoming a launch requirement, not an enterprise-only concern. As builders use Lovable, Bolt, Cursor, Claude Code, and similar tools to go from prompt to deployed product in hours, the most dangerous mistakes are often not sophisticated exploits—they are basic configuration gaps that nobody paused to inspect.
A recent post on r/SaaS made that point unusually concrete. The creator of an open-source, local command-line scanner said they tested it against a public GitHub project and found a hardcoded Supabase key alongside a database table with Row-Level Security (RLS) disabled. The tool was designed for AI-built apps and checks for familiar problems: committed secrets, exposed environment files, risky Supabase keys, and missing RLS protections. The claim is from the tool’s creator, so it should be read as a case study rather than an independently audited incident. But the underlying failure modes are well established—and increasingly common as code generation accelerates the path from idea to production. (reddit.com)
Why AI-generated app security is suddenly a founder problem
The appeal of AI coding tools is obvious. A solo founder can describe a dashboard, user accounts, payments, database tables, and admin workflows in plain English, then iterate on a functioning version in a fraction of the time a traditional build might take. That speed can turn a mockup into a real product before the team has established engineering review, deployment controls, or a security checklist.
The issue is not that generated code is uniquely insecure by definition. The issue is that AI-assisted development makes it easier to produce a larger surface area of code, integrations, configuration files, and database rules faster than a founder can understand them. The same prompt that creates a login flow may also create a client-side database connection, an overly broad query, a placeholder policy, or a .env file copied into the wrong place.
Secrets sprawl is already a broad software-development problem. GitGuardian reported 23.8 million secrets detected in public GitHub commits during 2024, while its subsequent 2026 report said 28.65 million newly hardcoded secrets appeared in public GitHub during 2025—a 34% increase. Those figures do not prove that AI tools caused every leak, but they show the scale of a problem that rapid, integration-heavy development can worsen. (blog.gitguardian.com)
For founders, the practical takeaway is simple: a product can look polished, pass a happy-path demo, and still expose customer data or privileged infrastructure. Security cannot be treated as the final polish after launch when users, data, and production credentials are already involved.
The Reddit case study: a scanner built for “vibe-coded” apps
The r/SaaS post was not a generic pitch for security software. Its author framed the project as a response to recurring mistakes in apps produced with AI-forward builders and coding assistants. The scanner is presented as a free, open-source Python CLI that runs locally, requires no signup, and does not need a live database connection to evaluate Supabase migration files. (reddit.com)
That design choice matters because code scanning can itself introduce a trust problem. A developer who wants to check a repository for secrets may reasonably hesitate before uploading source code, configuration, or credentials to an unknown SaaS service. A local-first tool reduces that exposure: the source stays on the developer’s machine, and the scan can become part of a local workflow before code is committed or deployed.
What the scanner is trying to catch
Based on the author’s description, its focus is deliberately narrow and practical:
- Hardcoded API keys and other credentials in application files.
- Accidentally committed
.envfiles and similar environment configuration. - Supabase
service_roleor secret keys placed in browser-accessible code. - Supabase tables in exposed schemas that lack RLS.
- Migration-level signals that authorization rules are incomplete or disabled.
That is a useful scope for early-stage teams. It does not replace a penetration test, a full software composition analysis program, or expert review of an application’s business logic. But it targets the mistakes that are both common and cheap to prevent.
Why migration-file analysis is useful
Reading migration files instead of connecting to a live database provides two benefits. First, a developer can scan a repository before the project is deployed, which is the best time to catch an unsafe schema change. Second, it enables checks in CI without giving a scanner privileged access to the production database.
There is an important limitation, though: migrations are an intended-state record, not always proof of the live state. A manual dashboard change, a failed migration, drift between environments, or a database created outside the expected workflow can mean the production setup differs from what the repository says. Static analysis is therefore excellent for prevention, but mature teams should eventually pair it with deployment checks and periodic verification of the actual environment.
The four AI app security mistakes that matter most
The Reddit post identifies a cluster of failures that commonly travel together. They are worth separating because the remediation for each is different.
1. Hardcoded secrets in source code
A hardcoded secret is a credential written directly into a source file, configuration file, frontend bundle, test fixture, or script. Examples include API keys for an LLM provider, a Stripe secret key, a database connection string, a cloud access token, or a Supabase secret key.
A key committed to a private repository is still a problem. Repositories get shared, cloned, forked, backed up, attached to CI systems, and occasionally made public. More importantly, deleting a key from the latest version of a file does not remove it from Git history. The right response to an exposed credential is generally rotation or revocation—not merely deleting the visible line.
GitHub offers secret scanning automatically and free for public repositories, and it scans supported secret patterns across repository history and other GitHub surfaces. That safety net is valuable, but it should not be confused with prevention for every code path, every private repository arrangement, or every organization-specific secret format. (docs.github.com)
2. .env files that escape local development
Environment files are convenient during development because they separate configuration from code. The problem begins when a generated project includes a real .env file in a template, a developer asks an AI tool to “make the app work,” or a deployment troubleshooting step leads to copying production values into a tracked file.
A robust baseline is uncomplicated:
- Commit
.env.example, never a real.envfile. - Put only placeholder variable names in the example file.
- Add
.env,.env.local, and production-specific variants to.gitignorewhere appropriate. - Store deployment values in the host’s encrypted environment-variable or secret manager settings.
- Scan both the working tree and Git history before making a repository public.
The distinction between example configuration and live configuration needs to remain clear to both humans and AI assistants. If a prompt contains real credentials, do not assume a coding tool will automatically protect them from appearing in generated files, terminal history, commit messages, or deployment instructions.
3. Privileged Supabase keys in the browser
Supabase’s key model is easy to misunderstand, especially in tutorials and AI-generated starter code. A publishable key can be used in a client application under the right data-access model. By contrast, Supabase states that secret and legacy service_role keys are never safe to expose because they bypass RLS and belong only on the backend. (supabase.com)
This creates a high-impact failure mode: a developer wants an admin action to work, asks an AI tool to fix an authorization error, and ends up placing a privileged key in frontend code. The UI may work perfectly. So will an attacker’s copied key.
The safer pattern is to move privileged operations into a server-side route, serverless function, or backend service. The browser should authenticate a user, call that controlled endpoint, and receive only the result it needs. The backend can then validate authorization, use an elevated credential when genuinely necessary, log the action, and apply rate limits or additional checks.
4. Missing or ineffective RLS policies
Row-Level Security is often the most misunderstood risk in Supabase-backed projects because it sits below the interface developers can see. A table can power a beautiful app while its access controls allow a user to read or alter data that belongs to everyone else.
Supabase’s documentation is direct: RLS should be enabled on every table in an exposed schema, which is commonly public. It also explains that grants govern whether a role can access an object, while RLS policies determine which rows that role can access. Both layers matter. (supabase.com)
A table with RLS enabled but an overly permissive policy is not secure. Nor is a table with a seemingly reasonable SELECT policy but unrestricted UPDATE, INSERT, or DELETE behavior. AI-generated database setups often need a second look because they may include broad rules intended to unblock early development, such as allowing any authenticated user to act on every row.
Why a public key plus disabled RLS can become a serious exposure
It is important not to call every exposed Supabase project URL or publishable key a breach. A client-facing Supabase configuration is designed to support browser access in many architectures. The security boundary is the combination of key type, database grants, RLS policies, authentication, and the actual data being requested.
The dangerous combination described in the case study is a public client-access path paired with a table that has RLS disabled or ineffective. In that scenario, the application may have unintentionally exposed a data API surface that can be queried outside the intended UI. Supabase warns that tables in an exposed schema without RLS can be accessible to roles with applicable grants, and recommends enabling RLS across such tables. (supabase.com)
A simple mental model for founders
Use this model when reviewing an AI-built Supabase app:
- Publishable key: Identifies the project and can be present in the client, but should operate under constrained database permissions and RLS.
- Authenticated user token: Represents the current user and should allow only actions justified by that user’s identity.
- RLS policy: Decides which rows that user can see or change.
- Secret or service-role key: A privileged backend credential that must never be delivered to the browser.
If one layer fails, the remaining layers should limit damage. If several layers fail together, a simple configuration error becomes a data-exposure event.
The community feedback got the workflow right: local scan, then CI gate
The top community response to the Reddit post focused less on the scanner’s detection list and more on its operating model: local-only secret scanning is a sensible choice, but a mature workflow should also fail CI when a new exposure is introduced and provide the exact remediation path.
That recommendation is stronger than “scan occasionally.” Occasional scans discover problems after they have accumulated. A CI gate changes the default: unsafe code does not merge unless someone resolves or explicitly reviews the finding.
GitHub’s push protection follows the same preventive principle for supported credential patterns. It blocks pushes containing detected secrets before they reach the repository, rather than only generating an alert after exposure. GitHub also supports custom patterns for organizations that need to recognize internal token formats. (docs.github.com)
What an actionable finding should include
A warning that says “possible security issue” is easy to ignore. A useful scanner or CI check should tell the builder:
- The file and line where the issue appears.
- The category of risk, such as exposed secret, missing RLS, or client-side privileged key.
- Why it matters in plain language.
- A recommended fix with safe defaults.
- Whether the scan has enough evidence to treat the result as high confidence.
- How to suppress a known false positive with a documented, reviewable exception.
This is especially important for non-specialists using AI tools. Security feedback should not require the recipient to become a database expert before they can ship safely.
A practical security pipeline for Lovable, Bolt, and Cursor projects
The best response to the rise of AI-built apps is not to slow every prototype to enterprise cadence. It is to install a few high-leverage controls at the moments where they are cheapest.
Before you prompt an AI coding tool
Do not paste production credentials, full customer exports, private tokens, or unredacted configuration files into a prompt. Use placeholders such as YOUR_STRIPE_SECRET_KEY or a mock data set. This protects both the product and the team from accidental leakage into generated code, shared chat history, logs, or copied examples.
Write down the intended trust boundaries before you build:
- Which operations should happen in the browser?
- Which actions require a trusted server?
- Which database tables contain user-owned or sensitive data?
- Which roles can read, create, edit, or delete each type of record?
- Which integrations require secrets, and where will those secrets live?
Even a one-page answer to these questions makes it easier to spot a generated implementation that violates the intended design.
Before every commit
Run a local scanner for secrets and configuration mistakes. Check the Git diff rather than only the final codebase; AI assistants can modify unrelated files, introduce new dependencies, or add setup artifacts while addressing a seemingly simple request.
Also review these high-risk files manually:
.env*, deployment config, and CI workflow files.supabase/migrationsand schema SQL.- Frontend initialization files for database, payments, analytics, and AI providers.
- Serverless functions, webhooks, and admin routes.
- Authentication middleware and route guards.
Before every merge
Make the pull request answer a short security checklist. The goal is not bureaucracy—it is forcing one explicit pause before production:
- Did this change add, move, or rotate any credential?
- Does any frontend code reference a privileged key?
- Did we add a table, view, bucket, or function that needs an authorization review?
- Are RLS policies enabled and tested for each operation?
- Did we introduce a dependency with permissions or install scripts that deserve review?
- Can a normal user access another user’s record by changing an ID in a URL or request?
CI should run secret scanning and static checks automatically. If your tool supports it, emit results in a common format such as SARIF so findings can show directly in code-review workflows. The specific scanner from the Reddit post may be useful as a lightweight local control, but teams should avoid designing their entire defense around one detection tool or one vendor’s patterns.
Before launch
Test the deployed application as different users. Create two ordinary accounts and attempt to read, modify, or delete the other account’s data. Try direct API requests, not just the UI. Review the built frontend bundle to confirm no privileged credentials appear in client-delivered JavaScript.
Finally, rotate any credential that was ever used in a demo, pasted into a prompt, copied into a repository, or shared broadly while troubleshooting. Rotation is often faster than proving a credential was never exposed.
Static scanning is necessary, but it is not enough
A local scanner that reads code and migrations is valuable because it catches predictable errors early. But it cannot fully understand product intent. A policy can be syntactically valid yet allow the wrong users to see the wrong records. A route may correctly check that someone is logged in but fail to check whether they own the resource they are changing.
That is why AI-generated app security needs layers rather than a single “security score.” A practical stack looks like this:
- Local pre-commit scanning to catch secrets and obvious unsafe patterns before code leaves a laptop.
- CI checks to block regressions and create an auditable record of exceptions.
- Platform protections such as GitHub secret scanning and push protection where available.
- Managed secrets in deployment settings or a dedicated secrets manager, rather than source files.
- Database authorization tests that prove user A cannot access user B’s rows.
- Periodic production review to find configuration drift, live permissions, exposed endpoints, and forgotten test data.
The order matters. The earlier a mistake is caught, the lower its cost. A secret caught locally takes seconds to remove. A secret pushed publicly can require incident review, key rotation, customer notification decisions, log analysis, and a careful rewrite of repository history.
How this compares with existing secret-scanning tools
Founders do not need to choose between an AI-app-focused scanner and established secret-scanning options. They solve overlapping but distinct problems.
GitHub secret scanning and push protection
GitHub is a strong repository-level safety net, especially for public projects where secret scanning runs automatically. Its pattern library, partner notifications, validity checks in certain contexts, and push protection can reduce exposure before a credential lands in Git history. (docs.github.com)
However, GitHub cannot replace local checks for teams that want feedback before pushing. It also does not inherently understand every application-specific authorization mistake in a Supabase migration.
General-purpose local secret scanners
Tools such as Gitleaks and TruffleHog are widely used options for scanning repositories, commits, and sometimes broader surfaces for credentials. They are a good fit when the primary concern is secret detection across a mixed stack: cloud providers, CI tokens, private keys, databases, SaaS integrations, and generic high-entropy strings.
Their limitation is not weakness; it is generality. They may not know that a particular SQL migration creates an exposed Supabase table without RLS, or that a project-specific starter template puts elevated access in the wrong layer.
AI-app and Supabase-specific scanners
The scanner discussed on Reddit represents a growing category: narrow tools built around repeated mistakes in a specific development ecosystem. The upside is opinionated checks and remediation that match the developer’s actual stack. The downside is coverage—specialized tools should complement, not displace, general secret scanning, dependency checks, and authorization testing.
The winning setup for a small SaaS is usually boring: one local scanner, one CI scanner, Git hosting protections, safe secret storage, and a short manual review of every change that touches authentication, payments, webhooks, or data access.
The deeper lesson: AI increases the need for guardrails, not security theater
It would be easy to turn stories like this into a vague warning about “vibe coding.” That misses the more useful conclusion. AI-assisted development can be exceptionally productive when the workflow includes controls that match its speed.
Security theater asks teams to fill out long forms while leaving real exposures untouched. Effective guardrails do the opposite: they catch credentials before commit, prevent privileged keys from reaching the client, force a review of database access rules, and provide a fix that a builder can apply immediately.
The most valuable tools will probably be the ones that translate security knowledge into the context of a generated app. Instead of saying “authorization issue,” they should say: “This profiles table is exposed through the Data API, RLS is disabled, and any role with table access may be able to query it. Enable RLS, add a policy scoped to auth.uid(), and test with two user accounts.” That is the level of specificity that helps a founder act.
What builders should do this week
If you have an app created with Lovable, Bolt, Cursor, Claude Code, or another AI coding workflow, a focused review can produce meaningful risk reduction in an afternoon.
- Search the whole repository and Git history for API keys, tokens, passwords, private keys, and
.envfiles. - Rotate anything that might have been exposed. Do not rely on deletion alone.
- Inspect browser-delivered code for Supabase secret or service-role keys and move privileged calls server-side.
- Review every exposed Supabase table, view, function, and storage policy. Enable RLS where required and test each CRUD action as multiple users.
- Add local scanning and a CI gate so the same class of mistake cannot quietly return next week.
- Turn on GitHub secret scanning and, where your plan and workflow allow it, push protection.
- Document a short incident playbook: revoke, rotate, assess access logs, clean history if appropriate, and notify affected parties if the facts require it.
The scanner in the Reddit post is a useful prompt to start this work, particularly for developers who want a local, open-source check geared toward Supabase-style AI projects. Its larger value is the reminder that the obvious flaws are still the ones worth eliminating first. (reddit.com)
Conclusion
AI-generated app security does not require every founder to become a full-time security engineer. It does require accepting that a working app is not automatically a safely deployed app.
The highest-return controls are straightforward: keep secrets out of code, never ship privileged keys to the browser, treat RLS as a core product requirement, scan locally, and block dangerous regressions in CI. Build those habits into the same rapid loop that produces prototypes, and AI becomes a force multiplier for shipping—not for avoidable exposure.
FAQ
What is AI-generated app security?
AI-generated app security is the practice of reviewing and protecting applications built partly or largely with AI coding tools. It includes secret management, authentication, authorization, database access rules, dependency review, secure deployment configuration, and testing for unintended access.
Is it safe to expose a Supabase key in frontend code?
A Supabase publishable key can be used client-side when database grants and RLS policies are correctly configured. Secret and legacy service_role keys must stay on the backend because they bypass RLS. (supabase.com)
Does enabling RLS solve all Supabase security issues?
No. RLS must be enabled, but policies also need to correctly enforce ownership and role-based access for SELECT, INSERT, UPDATE, and DELETE. Grants, views, functions, storage access, and server-side endpoints need review too. (supabase.com)
Should a small SaaS use a local secret scanner or CI scanning?
Use both when possible. Local scanning catches errors before code leaves a developer’s machine, while CI creates a shared, enforceable control that catches missed checks and blocks regressions before merge.
What should I do if I accidentally commit an API key?
Revoke or rotate it immediately, assess where it was exposed and what it could access, remove it from current code, update deployment secrets, and review repository history. Removing the line from the latest commit is not sufficient if the credential remains valid. GitHub’s remediation guidance likewise starts with identifying the secret and gathering context before completing remediation. (docs.github.com)