Build1 publisher3 min readPublished
A key in a test widget moved GoodBarber's secrecy decision into deterministic code
On July 22 a model wrote a forty-character API key into a page's JavaScript and declared the API not secret. GoodBarber now has the model state only how a key is sent and lets code default every key to secret.
The Engineer · Build desk

What happened
- On July 22 a one-line prompt in GoodBarber's pilot app builder produced a widget that wrote the author's own API key into the page's JavaScript, with the model's declaration marking the API as not secret.
- The generator no longer scans produced code for secrets and no longer lets the model decide secrecy; the model states one fact per key, how that key is sent.
- Deterministic code now makes the call, treating a declared key as secret unless it belongs to a family its provider documents as public.
- An earlier validator that matched unsafe JavaScript constructs against a list of regular expressions produced enough false positives to be switched off, and it was deleted on July 16.
- A July 13 plan had trusted the model's secret flag and deferred the stricter guard behind a written trigger; the leak met the trigger and the guard was committed at 15:01 the same afternoon.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- exposure The failure mode here is publication, not a failed build: a model that classifies correctly most of the time still ships a live key into a bundle the first time it is wrong.
- decision Anyone generating front-end code has to name an authority for the secret-or-public call, and the provider docs rule out both the model's own flag and a blanket ban on page keys.
- constraint Reading the declaration instead of the code bounds what the guard can see, so a key the generated widget acquires outside the declared list goes unclassified.
- precedent Attaching a named observation to a deferred safeguard gives the next reviewer something specific to check, and it is cheap to copy into any design note.
The declaration is the part worth copying. Alongside the widget code, the model has to emit a structured list of the APIs the widget calls and the keys each one needs, and both layers of the guard read that list instead of the generated JavaScript [7]. Once a key is classified as secret, its value goes from a masked field to a server-side proxy, and never reaches the model, the page or the bundle [6]. The post calls the code layer the one that matters, and its description of that layer is cut off.
The model got part of this right. The keys it marked secret without being told, according to the post, were the well-known ones: AI provider keys and payment secret keys [10]. The one it exposed was forty characters with no prefix, sent in a custom X-Api-Key header [2], which the author writes looks like what front-end tutorials do all day [25]. The instruction layer now opens with "DEFAULT TO SECRET when unsure" [8]. Its rule turns on documentation: a key is secret unless the provider explicitly documents it as public, publishable, anon, browser or search-only. And a key that authenticates your account is secret no matter how it is sent, custom header and query parameter included [9].
Scanning the output was ruled out on coverage as well as noise. The design notes for the secrets work carry the constraint in one line: the secret guard must not reintroduce pattern-matching on generated code [12]. GitHub redesigned its token format in 2021 because its old tokens were hard to tell from a SHA hash, and with identifiable prefixes it expected the false positive rate of secret scanning to fall to 0.5 percent [13]. That depends on the provider cooperating. GitGuardian's 2025 report counts 23,770,171 new hardcoded secrets in public GitHub commits during 2024 and classifies 58 percent of the leaks it detected as generic credentials, the class no provider-specific pattern describes [14]. That is about 13.8 million strings [15].
The opposite reflex fails on the same documentation the rule relies on. Stripe lists its publishable key as safe to expose, Firebase documents its API keys as public by design, Supabase documents its publishable key as safe to expose online, and Algolia its search-only key as safe for production front-end code [16]. Those keys identify a project, and authorization happens in security rules, row-level policies and restricted scopes [17]. A platform that enforced "never put a key in the page" would break every one of those integrations [18]. Default-deny has its own cost: a genuinely public key from a provider nobody has added to the documented-public list gets classified secret and routed through the proxy until someone adds it [23].
A safeguard deferred without a written trigger, the author wrote, is one that later never gets scheduled [21]. The condition that reopened this one was specific enough to check without a meeting: a leak by under-classification, observed [19].
Two things have to hold for this to transfer. The generator has to produce a declaration separate from the code, because with only code to read the guard becomes the scanner again. And someone has to keep the list of provider-documented public key families current, since the default sends everything else through the proxy [5][6]. Nothing had been released when the key turned up in the page, and the author calls a review before release the cheapest place to find a key in the wrong spot [27].
What to watch
- Whether GoodBarber publishes the code layer's list of provider-documented public key families, and how a new provider gets added.
- Whether the pilot builder ships to app owners outside GoodBarber with the stricter guard on by default.
- Whether GitGuardian's next annual count moves the 58 percent generic-credential share that makes prefix-based scanning insufficient.