Headline numbers
What we found
Grades
Why repositories were marked “Fix before sharing”
Most common problem categories
Lovable compared with Claude Code
The groups differ in what they trip over. In the Lovable sample, secret findings were common (62% had one), made up of a committed .env (46%) or a JWT-format token in code (30%), which in Lovable's Supabase setup is often the public anon key. In the Claude Code sample, critical package vulnerabilities (54% against 38%), risky code patterns (68% against 22%) and container setup problems (30% against 4%) were more common, so its strict “Fix before sharing” share was higher (60% against 38%).
Packages that showed up most often with known vulnerabilities
| Package | Repositories | Share |
|---|---|---|
source-map-js | 61 of 100 | 61% |
nanoid | 57 of 100 | 57% |
postcss | 56 of 100 | 56% |
react-router | 53 of 100 | 53% |
lodash | 53 of 100 | 53% |
@remix-run/router | 48 of 100 | 48% |
postcss-selector-parser | 44 of 100 | 44% |
brace-expansion | 43 of 100 | 43% |
Many of these are indirect dependencies that the app pulls in through its framework or build tools. A known vulnerability is not always reachable in a running app, but updating is usually the cheapest fix.
Packages behind the critical findings
| Package | Repositories | Share |
|---|---|---|
next | 16 of 100 | 16% |
proxy-addr | 14 of 100 | 14% |
websocket-driver | 8 of 100 | 8% |
protobufjs | 8 of 100 | 8% |
anyio | 7 of 100 | 7% |
pyjwt | 6 of 100 | 6% |
Risky code patterns found most often
| Pattern | Repositories |
|---|---|
| Text patterns built from changing input (can freeze the app) | 15 of 100 |
| Someone could read files on your server | 13 of 100 |
| File names built from changing input | 11 of 100 |
| Raw HTML inserted into pages (dangerouslySetInnerHTML) | 4 of 100 |
| Text patterns that can be made very slow (ReDoS) | 3 of 100 |
| Someone could run commands on your server | 3 of 100 |
Code patterns need a human look: a pattern is only a real problem if input from users or other systems can reach it. The scanner also raised lower-confidence “worth a look” hints, most often for HTML built inside text strings (30 repositories) and Log or message text built from changing input (27); these are not counted above.
What this means if you build apps with AI
Your app inherits old packages
Most apps sit on hundreds of open-source packages. If the lockfile was created months ago and never updated, it keeps versions with published vulnerabilities, which attackers can look up as easily as you can. Updating them is usually a single command plus a test.
A committed .env is a public .env
On a public repository, anyone can read every file in the history. In Lovable projects the .env often holds only the Supabase address and the public anon key, which is fine. Anything else in it, such as a service_role, Stripe secret or OpenAI key, should be treated as leaked and replaced.
Not every token is a secret
The Supabase anon key is a JWT and is meant to be in front-end code, as long as row-level security protects every table. The service_role key is also a JWT and must never be there. A pattern scanner can't tell them apart without reading the value, so check which one yours is.
Code patterns need a second look
Findings such as text patterns built from input, redirects or raw HTML are only dangerous if user input reaches them. Ask your AI tool to explain each one and show where the input comes from.
What to do
- Run the free check on your own app:
pip install appledger, thenpython -m appledger path/to/your-app, or add it to Claude Code (how). It is the same engine we used for this report. - Fix every “Fix before sharing” item first. For keys: create a new key at the provider, revoke the old one, then store the new one outside the code. Removing it from the latest commit is not enough.
- Update outdated packages (
npm updateornpm audit fix), run the app, and check again. - Check what no code scanner can see: row-level security in Supabase (its Security Advisor helps), who can log in, and whether one user can reach another user's data. See the Lovable and Bolt guide.
Check your own app before you share it.
Run the free checkMethodology and limitations
- Sample
- 100 public GitHub repositories: 50 built with Lovable, 50 built with Claude Code. Collected and scanned on 2026-10-14.
- Lovable
- Found with GitHub code search for
lovable-taggerinpackage.jsonor “Welcome to your Lovable project” inREADME.md; the marker was verified at the repository root after cloning. - Claude Code
- Found with GitHub code search for a root
CLAUDE.mdcontaining common build terms (for example “npm run dev”, “pip install”, “supabase”); kept only with an app manifest (package.json,requirements.txt,pyproject.toml,go.mod…) at the root or one level down, and without Lovable markers. ACLAUDE.mdshows Claude Code was used, not that it wrote all of the code. - Both groups
- Pushed in 2026; not forks, GitHub templates or archived; names, descriptions and topics suggesting templates, starters, tutorials, examples or agent/prompt tooling were excluded; at least 5 source files; at most 50 MB. Candidates were shuffled with a fixed seed and taken in order until 50 per builder were scanned. Lovable: 166 reviewed, 50 scanned; skipped: 101 not pushed in 2026, 9 over 50 MB, 5 fork/template/archived, 1 template/tutorial/tooling by name. Claude Code: 70 reviewed, 50 scanned; skipped: 8 over 50 MB, 4 not pushed in 2026, 4 template/tutorial/tooling by name, 3 marker not verified, 1 under 5 source files.
- Engine
- AppLedger 0.2.2, using the same steps as the hosted check: only files a hosted check would upload (no ignored, media, data or secrets files), scanned with Trivy 0.74.0 (vulnerability database of 2026-10-13) and Opengrep 1.30.2, plus AppLedger's check for secrets files tracked by git (by file name only). Shallow clones, one at a time; each clone was deleted right after its scan.
- Score
- Starts at 100; each “Fix before sharing” finding keeps 75% of the score, each “Fix soon” 93%, each “Good to know” 99%. Grades: A 90+, B 75+, C 55+, D 30+, F below 30.
- Security only
- The scores, grades and levels on this page leave out Opengrep rules whose own category is not “security”, for example
jsx-not-internationalized(portability),react-props-spreading(best-practice),dockerfile-source-not-pinned(best-practice). Those style and translation rules fire on almost every React app and would push most scores to zero without saying anything about security. With them, the median score is 0; both versions are in the data file.
- Small, non-random sample. 100 repositories found through GitHub code search, which favours some repositories over others. Public repositories may differ from private ones, and some are likely experiments rather than live apps. Results don't describe all apps built with these tools.
- Static scanning only. We read code; we didn't run the apps or visit any live site. A scan can't check login and permission logic, Supabase row-level security, Firebase rules or other settings that live outside the repository, which are common causes of real data exposure. A clean result is not a guarantee.
- Secrets are pattern matches. Exposed-secret counts come from Trivy's and Opengrep's secret rules and from file names (for example a committed
.env, whose contents we never opened). They may include test or placeholder values and publishable keys that are meant to be public, such as the Supabase anon key. We didn't print, store, use or test any value. The 30 key-pattern findings marked “Fix before sharing” came from these scanner rules: jwt-token (28), stripe-publishable-token (1), detected-github-token (1); 2 of them were in files whose path suggests examples, tests or documentation. - Known vulnerabilities aren't always exploitable. Package findings come from version numbers in lockfiles. Whether a vulnerability matters depends on how the app uses the package.
- Scanner rules change. Results reflect the rule sets and vulnerability database on 2026-10-14. Older projects collect more known vulnerabilities over time.
- No names. We publish aggregate numbers only. Repository names, owners, file paths and secret values are not in this report or the data file, and the private list of scanned repositories was deleted after the run. We didn't contact owners.
How to cite
AppLedger (2026). State of vibe-coded app security 2026: an aggregate scan of 100 public repositories built with Lovable and Claude Code. https://appledger.net/reports/vibe-coded-app-security-2026/
Data: data.json (aggregate and anonymous, CC BY 4.0). Found a mistake? Write to bruno@contenta-software.com and we will correct it here.