Back to Blog
May 13, 2026

The Stripe Secret Key in the Frontend Bundle: 4 Months of Silent Exposure

Viktor Bulanek
Founder & CTO, Penetrify
MSc IT Security · 20+ years in security · 4x Ex-CTO

The marketplace had been running for eight months. Two co-founders, neither with a security background, had built it on Bubble.io with Stripe Connect for payments. It had processed over $40,000 in transactions, had 1,500 registered users, and was growing steadily through word of mouth.

Twelve minutes into the Penetrify scan, a Critical finding came back: the Stripe secret API key was embedded in a client-side JavaScript file being served to every visitor's browser. It had been there since launch. Four months of full read/write access to their entire Stripe account, available to anyone who opened DevTools.

This is the story of how a $40,000 business almost became a cautionary tale.


The Stripe API Key You Should Never Expose

Stripe issues two types of API keys: publishable keys and secret keys.

The publishable key (pk_live_...) is designed to be used in frontend code. It can only perform limited operations — creating payment method tokens, confirming payments — and cannot access sensitive account data. It's safe to expose in client-side JavaScript.

The secret key (sk_live_...) is an entirely different matter. With a Stripe secret key, you can:

  • List all customers, payment methods, and subscriptions
  • Read full card fingerprints and billing addresses for all customers
  • Issue arbitrary refunds on any transaction
  • Create charges against any saved payment method
  • Modify or delete payout schedules and bank account details
  • Access all Connected Accounts (in this case, all seller payment accounts on the marketplace)
  • Retrieve bank account details for every seller who had onboarded through Stripe Connect

The Stripe secret key is the master key to your entire payment infrastructure. It belongs only in server-side code, in environment variables that are never sent to the browser.


How It Ended Up in the Bundle

Bubble.io is a no-code platform that lets you build full-stack web applications without writing code. It has a built-in workflow system for server-side logic and an API connector for external services. For a two-person team without engineering backgrounds, it's a legitimate way to ship a real product quickly.

The Stripe secret key ended up in the frontend for a reason that will be familiar to anyone who has built on a no-code platform under time pressure: it worked.

During development, the team needed to make Stripe API calls from Bubble workflows. They added the secret key to the API connector configuration. At some point in the configuration — whether a misunderstanding of client-side vs. server-side execution, or a Bubble configuration detail that wasn't obvious — the key ended up being included in the JavaScript payload sent to the browser. The payment flows worked. The transactions processed correctly. There was no error, no warning, no obvious symptom.

Bubble's platform handles a lot of server-side execution correctly by default, but the boundary between what runs in the browser and what runs on Bubble's servers isn't always visually obvious in the no-code builder. This is a well-documented risk in the Bubble developer community, but it's easy to miss when you're focused on making the product work rather than auditing what data your app sends to the client.


What the Exposure Actually Meant

Let's be specific about what was at risk during those four months.

Anyone who visited the marketplace could open Chrome DevTools, navigate to the Sources or Network tab, search through the JavaScript files for sk_live_, and find the key. This requires no hacking tools, no special knowledge, and no vulnerability beyond the ability to right-click and inspect a web page.

With that key, they could have:

  • Drained the business's Stripe balance by issuing refunds on completed transactions, reversing revenue that had already been earned
  • Enumerated all customer records including names, email addresses, partial card details, and billing addresses — a reportable data breach under GDPR and various US state privacy laws
  • Accessed seller bank account details for every seller who had connected their payout account through Stripe Connect — names, account numbers, routing numbers
  • Modified payout schedules to redirect seller payouts to attacker-controlled accounts
  • Created fraudulent charges against any saved customer payment method, up to Stripe's limits for the account

Any one of these outcomes would have ended the business. Combined, they represent the kind of catastrophic breach that makes it into security conference talks.

The Stripe key had been exposed for 4 months. During that time, approximately 8,000 people had visited the marketplace. Any of them could have found it.

The Other Findings

The Stripe key was the most severe finding, but the scan surfaced four additional issues:

MEDIUM — Bubble privacy rules misconfigured

Bubble's privacy rules control which database fields are visible to different user roles. The seller profile records — which included bank account details entered during Stripe Connect onboarding — were visible to any authenticated user via Bubble's data API. Even without the Stripe key, any logged-in buyer could have queried for seller financial information.

MEDIUM — Account enumeration via password reset

The password reset flow returned different responses for registered vs. unregistered email addresses. A request for a registered email returned "Check your inbox"; a request for an unregistered email returned "No account found." This allows an attacker to build a list of which email addresses have accounts on the platform — useful for targeted phishing or credential stuffing.

MEDIUM — No Content Security Policy

The application returned no Content-Security-Policy header. The search functionality reflected user-supplied input without encoding in some contexts, making reflected XSS possible. Without a CSP, an XSS payload could exfiltrate session tokens, make authenticated API calls on behalf of the victim, or inject malicious scripts into the page for other visitors.

LOW — CORS wildcard

The API returned Access-Control-Allow-Origin: *, allowing any website to make cross-origin requests to the API endpoints and read the responses. For endpoints returning sensitive data, this enables cross-site data exfiltration from a malicious page the victim visits.


The Response: Immediate and Effective

The founders acted within the hour of receiving the report.

The first step was to rotate the compromised Stripe key. In the Stripe dashboard, under Developers → API Keys, the live secret key can be rolled — generating a new key and immediately invalidating the old one. This took approximately two minutes. From that moment, anyone who had extracted the exposed key could no longer use it.

The second step was to audit Stripe's event logs for unauthorized activity. Stripe's Dashboard provides a full log of every API call made with your keys, including the IP address and timestamp of each request. The founders reviewed the event log for the previous four months looking for anomalous calls — refunds they didn't issue, customers they didn't create, payout changes they didn't make. They found none. The key had been exposed but — as far as could be determined — had not been actively abused.

The third step was to fix the Bubble configuration. Working with a Bubble developer they hired for a few hours, they moved all Stripe API calls into Bubble's server-side backend workflows, where API keys are not transmitted to the browser. The Bubble privacy rules were also corrected to restrict seller financial data to the relevant seller account only.


How to Find This in Your Own Application

If you're running a Bubble, Webflow, or any other no-code application that integrates with Stripe, here's how to check whether you have this issue:

  1. Open your application in an incognito window.
  2. Open Chrome DevTools (F12) → Network tab.
  3. Reload the page.
  4. In the Network tab, look for JavaScript files. For each one, click it and search (Ctrl+F) for sk_live_.
  5. Also check the Sources tab. Use Ctrl+Shift+F to search across all loaded scripts for sk_live_.

If you find your Stripe secret key in any of these files, rotate it immediately before doing anything else, then investigate how it got there.

This same check applies to any other sensitive API key: OpenAI, Twilio, SendGrid, AWS, Mailchimp. Any key with write access or access to sensitive data that you find in client-side JavaScript should be treated as compromised and rotated immediately.


Why This Pattern Persists

Secret key exposure in frontend bundles is not a new vulnerability class. It's been a known, well-documented risk for as long as web applications have used third-party APIs. So why does it keep happening?

The answer is that the development experience makes it easy. No-code platforms and modern JavaScript frameworks blur the boundary between client and server in ways that weren't present in earlier web development models. Environment variables prefixed with NEXT_PUBLIC_ are intentionally sent to the browser; those without the prefix aren't. Bubble's execution context depends on which workflow type you're using. Vite and webpack bundle configurations determine what ends up in the browser.

These boundaries are documented but not enforced at the tooling level. There's no build-time error when you accidentally expose a secret key. The application works correctly. The exposure is silent, indefinite, and growing every day that the key remains valid.

The only reliable defense is to scan for it explicitly — and to rotate quickly when you find it.

Frequently Asked Questions

What types of vulnerabilities does Penetrify detect?

Penetrify detects all OWASP Top 10 vulnerability categories including SQL injection, XSS, CSRF, IDOR, broken authentication, security misconfigurations, and sensitive data exposure. It also tests API security, session management, and common misconfigurations in Supabase, Firebase, and Bubble.

How long does an AI penetration test take?

A quick scan completes in 15–30 minutes. A standard scan runs 1–2 hours with broader coverage. A deep scan can run several hours for complex applications.

What does a Penetrify report include?

Every report includes an executive summary, overall security score, severity-classified findings (Critical, High, Medium, Low), step-by-step reproduction steps, and concrete remediation guidance written for developers — not compliance officers.

Back to Blog