Engineering
What we found scanning 2,000 React apps for exposed keys

Oren Bassett
·
·
4 min read

Refit brings an existing React app into Chamfer. It scans the repository, moves secrets out of the source and wraps the app in sign-in, roles and logging. Before we opened it to Next.js projects on July 21, we ran the scanner over 2,000 internal repos that customers had shared with us for testing.
The results were less dramatic than you might expect, and more useful.
What we scanned
The repos came from 310 companies. Most were small: the median app had 41 components and 6 data calls. About a third were written with an AI coding assistant in the last year. The rest were older admin panels kept alive by one or two engineers.
Customers opted in through a support ticket. Each repo was scanned in an isolated environment and deleted after 14 days; we kept only the counts.
We looked for four things: credentials in the source, routes that return data without an auth check, writes to production tables straight from the browser, and dependencies with published CVEs.
The numbers
23% had at least one live-looking API key in the source or in a committed .env file.
31% had at least one route that returned records without checking who asked.
12% wrote to a production table directly from the browser.
64% carried a dependency with a published CVE, most of them rated low.
As far as the providers’ logs could show, none of the keys we confirmed had been used from outside the company. Every affected customer heard from us the same day, with the file and line.
Repos written with AI help and repos written by hand scored almost the same. Age made the difference: repos untouched for more than a year were twice as likely to hold an exposed key.
Most of the keys we found weren’t careless. They were left behind by an app that outlived the person who built it.
How the scanner tells a key from noise
Pattern matching alone throws too many false alarms. The scanner weighs three signals: the token’s shape (prefixes like sk_live_), its entropy, and where it’s used. A high-entropy string passed to a payment client gets flagged. The same string in a test fixture is noted and left alone. On the sample, weighing all three cut false positives from 1 in 3 to about 1 in 25, without missing any of the keys we had planted for testing.
What happens to a flagged key
Nothing is deleted automatically. The value moves into your workspace’s secret store, the call is rewritten to use a server-side resource, and the change appears in the scan report for a person to approve. Rotating the key is still on you, so the report links to each provider’s rotation page.
What we changed before launch
Three fixes came out of the sample. Scans now finish in under two minutes for 95% of repos, down from eight, because vendored folders are skipped. Route checks understand Next.js middleware, which removed most false alarms on App Router projects. And the report groups findings by fix, so a reviewer sees “move 4 keys” instead of four separate warnings.
The report now opens with a short summary written for the reviewer rather than the engineer: what the app reads, what it writes, and what will change when it moves in.
If you maintain an older panel
You don’t need Chamfer to act on any of this. Search your repos for committed .env files, add a secret scanner to CI, and check that every route returning records has an auth check. Our secret-detection rules are published in the docs under an open license, so you can run the same checks in your own pipeline. If you’d rather hand the job over, Refit for Next.js is on Team plans and up.
Keep reading

Build Chamfer apps from Claude, Cursor or Codex
Chamfer MCP is live on every plan. Connect your editor, build under your own role, and every change still lands in the Logbook with a name and a diff.

Mei Lin Tan
·

Writing Specs your auditor can actually read
Specs are company-wide rules every new app follows from its first build. Here's how to write them so builders, reviewers and auditors read the same thing.

Mei Lin Tan
·