---
title: "Stanford Found 1,748 API Keys on the Open Web — Here's How to Stop Being One of Them"
description: "A Stanford study scanned 10 million websites and found 1,748 live API credentials exposed in JavaScript bundles. Here's what went wrong and how to fix it."
canonicalUrl: "https://zuplo.com/blog/2026/04/09/stanford-keys-on-doormats-api-key-security-lessons"
pageType: "blog"
date: "2026-04-09"
authors: "nate"
tags: "API Key Authentication"
image: "https://zuplo.com/og?text=Stanford%20Found%201%2C748%20API%20Keys%20on%20the%20Open%20Web"
---
Researchers at Stanford and UC Davis just published a study that should make
every API team uncomfortable. They scanned roughly 10 million web pages, ran
[TruffleHog](https://github.com/trufflesecurity/trufflehog) against every one of
them, and found **1,748 verified, live API credentials** scattered across 9,804
websites spanning 5,693 distinct domains. The credentials belonged to
multinational corporations, critical infrastructure entities, and government
agencies. AWS keys. Stripe keys. OpenAI keys. All sitting in plain sight on the
public internet.

The paper is called
["Keys on Doormats: Exposed API Credentials on the Web"](https://arxiv.org/html/2603.12498v1),
and it landed during a week where every major tech outlet picked it up — The
Register, CyberNews, and IBTimes all ran coverage. The timing is not a
coincidence. API credential exposure is not a niche problem anymore. It is the
default state of the web.

## The Scale of the Problem

The study examined 14 major service providers and verified every credential it
found. The results break down like this:

- **AWS** — 283 verified credentials exposed across 4,693 websites. One belonged
  to a Global Systemically Important Financial Institution (G-SIFI) with access
  to Lambda, RDS, and Key Management Service.
- **Stripe** — 277 credentials with a 42% verification rate. Live payment
  processing keys sitting in production JavaScript bundles.
- **OpenAI** — 181 credentials with an 18% verification rate. The rapid adoption
  of AI APIs is creating a new generation of key sprawl.
- **GitHub** — 119 credentials, including one that granted full repository
  privileges to a firmware developer whose code powers drones and
  remote-controlled devices globally.

And here is the part that should really keep you up at night: exposed
credentials remained publicly accessible for an **average of 12 months**. Some
persisted for up to five years. The majority went unaddressed for months.

## JavaScript Build Tools Are the #1 Vector

The most actionable finding in the study is the root cause analysis. **84% of
exposed credentials appeared in JavaScript resources**, and of those, **62% were
inside bundled files generated by tools like Webpack**. Only 8% appeared in HTML
resources.

This means the majority of credential leaks are not developers accidentally
pasting a key into an HTML template. They are build tools — Webpack, Vite,
Rollup — pulling environment variables into client-side bundles during the build
process. A developer sets `REACT_APP_API_KEY` or `NEXT_PUBLIC_STRIPE_KEY` in
their `.env` file, and the bundler dutifully bakes it into a JavaScript file
that gets served to every visitor.

The encoding makes it worse, not better. The study found that 67% of credentials
were exposed in plain text, 18% as escaped Unicode sequences, and 15% as
Base64-encoded strings. None of these are security measures. They are artifacts
of how JavaScript bundlers serialize string values. Anyone with browser DevTools
can decode them in seconds.

The researchers put it bluntly: the root cause is that **build-time environment
variable substitution treats all variables the same**, whether they hold a
public site title or a secret AWS access key. Frameworks like Next.js and Create
React App use prefixes (`NEXT_PUBLIC_`, `REACT_APP_`) to mark variables as safe
for client-side inclusion, but the study shows that developers routinely ignore
or misunderstand these conventions.

## The $82K Connection

If this sounds familiar, it should. Just three weeks before this study dropped,
we wrote about the
[Google Gemini API key vulnerability](/blog/google-api-key-gemini-vulnerability-lessons)
where nearly 3,000 public Google API keys — originally harmless billing
identifiers for services like Maps — silently gained access to Gemini AI
endpoints. One developer racked up $82,314 in charges in a single day.

The Stanford study validates the same pattern at a much larger scale. Keys that
were embedded in client-side code years ago, when the perceived risk was low,
are now sitting on a web that has fundamentally changed around them. AWS keys
that once accessed a single S3 bucket might now reach services the developer
never intended. Stripe test keys might have been promoted to production. OpenAI
keys that cost pennies per call in 2024 now access models that cost dollars per
call.

The blast radius of an exposed key is not static. It grows every time the
backing service adds a new capability or changes its pricing. And the Stanford
data shows that keys stick around for months or years — long enough for the risk
profile to shift dramatically beneath them.

## The Fix the Researchers Recommend

The paper's recommendations read like a product requirements document for an API
gateway. The researchers explicitly call for:

1. **Routing sensitive API calls through backend proxies** instead of making
   them directly from client-side JavaScript
2. **Using separate, easily rotatable keys** rather than long-lived static
   credentials
3. **Integrating credential scanning into CI/CD pipelines** to catch leaks
   before they reach production
4. **Service providers deploying automated detection** of leaked keys on public
   webpages

These are not theoretical suggestions. They are describing the architecture that
an API gateway like Zuplo provides out of the box.

## How Zuplo Addresses Every Root Cause

The Stanford study identifies a clear chain of failures: keys get embedded in
client code, build tools bake them into production bundles, and they persist for
months because nobody detects or rotates them. Zuplo breaks this chain at
multiple points.

### Backend Proxy Architecture: Keep Keys Server-Side

The single most effective fix is also the simplest: do not put secret keys in
client-side code. Period.

Zuplo sits between your frontend and your backend APIs as a
[fully managed API gateway](https://zuplo.com/docs/articles/api-key-management).
Your frontend authenticates to Zuplo using a consumer-specific API key, and
Zuplo handles the upstream call to AWS, Stripe, OpenAI, or any other service
using server-side credentials that never touch a JavaScript bundle. The secret
keys stay in Zuplo's
[secure environment variable storage](https://zuplo.com/docs/articles/environment-variables)
— not in your `.env` file, not in your Webpack config, and certainly not in your
production HTML.

This is exactly what the Stanford researchers recommend when they call for
"routing sensitive API calls through backend proxies."

### Managed API Key Authentication: No More DIY Key Management

Zuplo's
[API key authentication](https://zuplo.com/docs/policies/api-key-inbound) gives
your API consumers keys that are purpose-built for secure distribution. Keys are
stored as irretrievable, one-way hashes — the original key value cannot be
reconstructed even if the underlying storage is breached. Each key is scoped to
a specific consumer with its own metadata, permissions, and rate limits.

Because consumers get their keys through Zuplo's
[developer portal](https://zuplo.com/docs/dev-portal) — not by copying values
from a `.env` file — there is no reason to embed keys in build-time
configuration at all. The pattern that caused 84% of the exposures in the
Stanford study simply does not exist.

### Instant Key Rotation: Months of Exposure Become Seconds

The Stanford data shows that exposed credentials remained live for an average of
12 months. Even after the researchers notified 2,435 affected organizations,
only 50% removed the exposed credentials within 14 days — and just 26% actually
revoked the keys (meaning the rest only removed the public exposure while
leaving the credentials active).

Zuplo supports
[instant key rolling](https://zuplo.com/docs/articles/api-key-leak-detection#roll-the-api-key)
through both the API and the developer portal. Rolling a key creates a new
credential and sets an expiration on all existing keys for that consumer — you
can expire them immediately for maximum security or set a short grace period so
consumers have time to update. Changes propagate globally across Zuplo's 300+
edge locations in seconds, not hours.

### GitHub Secret Scanning: Catch Leaks Before They Go Live

Here is where Zuplo closes a gap the study specifically calls out. The
researchers recommend that service providers "deploy automated detection of
leaked keys." Zuplo has been doing this since 2022.

Zuplo is an official
[GitHub secret scanning partner](https://github.blog/changelog/2022-07-13-zuplo-is-now-a-github-secret-scanning-partner/).
Every Zuplo API key uses a distinctive `zpka_` prefix that GitHub's scanners
recognize. If a Zuplo-issued API key is accidentally committed to any GitHub
repository — public or private — GitHub notifies Zuplo, and Zuplo immediately
alerts you via email and in-app notifications. From there, you can
[roll the key](https://zuplo.com/docs/articles/api-key-leak-detection) with a
single API call or portal click.

This is not a premium add-on.
[API key leak detection](https://zuplo.com/docs/articles/api-key-leak-detection)
is available to every Zuplo customer, including free tier. The Stanford study
found that 62% of leaked credentials were buried in Webpack bundles where manual
code review would never catch them. Automated scanning is the only realistic
defense at scale, and Zuplo bakes it into the platform by default.

### Per-Key Rate Limiting: Cap the Blast Radius

Even with leak detection and fast rotation, defense in depth matters. If a key
is compromised before you can rotate it, rate limits are your circuit breaker.

Zuplo's
[rate limiting policies](https://zuplo.com/docs/policies/rate-limit-inbound) can
be configured per API key, so every consumer gets their own ceiling. You can set
request-per-minute limits, daily quotas, or custom policies based on consumer
metadata. This is the difference between a compromised key generating an $82,000
bill and a compromised key hitting a rate limit after $50 of usage.

## The Bigger Picture

The Stanford study is the latest in a pattern that is becoming impossible to
ignore. In February, the
[Google Gemini API key incident](/blog/google-api-key-gemini-vulnerability-lessons)
showed what happens when exposed keys gain new privileges. In March, Wallarm's
[2026 API ThreatStats Report](/blog/wallarm-2026-api-threatstats-api-security)
confirmed that APIs are now the #1 exploited attack surface, with 59% of API
vulnerabilities requiring no authentication at all.

The common thread across all three is that ad-hoc API credential management does
not work. It does not work for startups. It does not work for enterprises. The
Stanford study found exposed keys belonging to organizations of every size,
including financial institutions and government agencies. If well-resourced
teams with dedicated security staff are failing at this, the answer is not "try
harder at DIY key management." The answer is to use infrastructure that makes
the insecure path impossible.

That means: backend proxies so secrets never reach client code. Managed key
authentication so credentials are hashed, scoped, and rotatable. Automated leak
detection so exposure is measured in minutes, not months. Per-key rate limits so
a compromised credential cannot cause catastrophic damage.

That is what Zuplo provides. If you want to see how it works,
[start for free](https://portal.zuplo.com/signup) and add API key authentication
to your API in minutes. For a deeper dive into implementation patterns, read our
guide on
[how to implement API key authentication](https://zuplo.com/learning-center/how-to-implement-api-key-authentication)
or explore the
[API key authentication best practices](https://zuplo.com/blog/api-key-authentication).