Keys to the Kingdom Live Stripe Credentials Exposed via Unauthenticated OAuth Endpoint
There is a particular category of finding that stops you mid-test. Not because it is technically complex, but because of what you are looking at. A single unauthenticated GET request that returns live payment credentials for a platform processing real customer transactions is one such finding.
This is the account of a critical information disclosure vulnerability identified during a black-box web application assessment. The application was a SaaS platform with built-in payment processing and third-party integrations. No credentials were required to reproduce the issue. No authentication bypass was needed. The endpoint was simply open.
Discovery
During the assessment, we were mapping the application’s API surface methodically, working through endpoints and observing what each one returned. One endpoint in particular caught our attention.
A GET request to “/api/oauth/provider/” with no authentication headers returned a JSON array containing the full OAuth configuration for every third-party integration the platform had configured. This included client IDs, client secrets, authorisation URLs, token URLs, redirect URIs, and publishable keys across multiple services and environments.
What came back was not just a dev key someone had forgotten to rotate. It was a complete dump of all integration credentials the application held, across all environments, including production.
What Was Exposed
The response contained credentials for several services and environments. Among them:
Procore: The construction project management integration returned the full client secret along with its OAuth configuration. Procore is used by construction companies to manage project data, financials, and subcontractor information. Access to these credentials would allow a threat actor to authenticate as the application against Procore’s API and interact with all connected project data.
Stripe (Development and Staging) Two separate Stripe test environment configurations were present, each with its own client ID, client secret, and publishable key. These alone would be a notable finding on any assessment.
Stripe (Live Production) The production Stripe integration was also present in the response. This included a live secret key prefixed sk_live_, a live publishable key prefixed pk_live_, and the full OAuth configuration for the live payment environment.
This was not a test key. It was the live key actively processing real customer payments.
Verifying the Impact
To demonstrate the full extent of what was accessible, we used the exposed live secret key against the Stripe API directly from the command line. We did not interact with any customer payment methods or initiate any transactions.
Querying the customers endpoint returned a list of real customer records, including names, email addresses, and account details for organisations that had transacted through the platform. The livemode: true field in every response confirmed that these were not test records.
1
2
3
4
curl https://api.stripe.com/v1/customers \
-u "sk_live_[redacted]": \
-G \
-d limit=3
Querying the charges endpoint returned a list of real transactions, including full billing details, customer names, addresses, payment amounts, and invoice references.
1
2
3
4
curl https://api.stripe.com/v1/charges \
-u "sk_live_[redacted]": \
-G \
-d limit=10
To confirm the key was actively in use and not simply a dormant credential, we retrieved a payment receipt for one of the listed transactions. The receipt was genuine, associated with a real invoice, and confirmed a live payment had been processed through the platform.
The key worked. The data was real. The exposure was complete.
What a Threat Actor Could Do
With a live Stripe secret key, an attacker has full programmatic access to the connected Stripe account. This goes significantly beyond simply viewing transaction history.
The Stripe API with a secret key allows enumerating all customers and their stored payment methods, retrieving the full transaction history across the account, issuing refunds against existing charges, creating new charges against stored customer payment methods, and modifying customer and subscription records.
In a platform processing payments on behalf of multiple clients, the downstream impact extends to every organisation whose payments were processed through that Stripe account. Customer financial data, billing addresses, and payment histories would all be accessible.
The Procore credentials presented a separate but equally significant risk. An attacker authenticating against Procore’s API as the application would have access to all project data, financial records, and subcontractor information for every connected construction project.
Root Cause
The endpoint was returning the application’s internal OAuth configuration, likely intended for use during the OAuth authorisation flow to populate redirect parameters and provider settings on the frontend. The mistake was that the endpoint was accessible without any authentication, and the response included server-side secrets that should never leave the backend.
Client IDs and publishable keys are designed to be public-facing. Client secrets and live API keys are not. The response made no distinction between the two, returning all the data the application held for each integration in a single unauthenticated call.
The fix is straightforward. The endpoint should require authentication before returning any configuration data. Beyond that, server-side secrets should never be included in any response sent to the client, regardless of the authentication state. The frontend does not need a Stripe secret key. Only the server does.
Takeaways
OAuth integration endpoints deserve the same scrutiny as any other authenticated API surface. An endpoint that exists to support an authorisation flow is still an endpoint, and if it is returning credentials rather than just redirect parameters, it needs to be protected accordingly.
Live payment credentials sitting in an unauthenticated API response are not a subtle misconfiguration. It is the kind of finding that requires immediate revocation and rotation of every exposed key before anything else happens. The assessment was paused at this point, and the client was notified directly so that remediation could begin before the engagement continued.
This was an authorised engagement conducted with the client’s full knowledge and consent. All identifying details, including client name, customer names, transaction details, and credentials, have been fully redacted and anonymised.