· Vuldesk Security Team · Security Research · 6 min read
OAuth Token Security in SaaS Apps: The Breach Nobody Talks About
Social schedulers, LinkedIn automation tools, and sales platforms all store OAuth tokens for their customers. Here is what happens when the token storage layer has gaps — and what we find when we test it.
If your SaaS product integrates with Twitter, LinkedIn, Google, or any other platform on behalf of your customers, you are storing OAuth tokens. And if those tokens are not handled correctly, a single vulnerability in your application does not just expose your database — it exposes every connected account belonging to every customer you have.
This is the attack surface most bootstrapped SaaS founders have never thought about.
What OAuth tokens actually are
When a user connects their Twitter account to your social media scheduler, they authorize your app to act on their behalf. Twitter gives your app an access token — a credential that allows you to post tweets, read DMs, or fetch analytics as if you were that user.
Your app stores that token somewhere — a database column, an environment variable, an encrypted secrets store. The token is valid until the user revokes it or it expires. For many platforms, tokens never expire.
The blast radius question: If an attacker finds a vulnerability in your application and can read from your database or your secrets store, how many Twitter accounts can they now control?
For a social media scheduler with 500 customers, the answer might be 500 Twitter accounts, 500 LinkedIn accounts, and 500 Instagram accounts — simultaneously, with no further effort required.
The five token security failures we find most often
1. Tokens stored in plaintext in the database
This is the most common finding. Developers often treat OAuth tokens like session cookies — necessary to store, not particularly sensitive. In practice, a leaked database backup or a SQL injection vulnerability instantly yields usable credentials for every connected account.
What it looks like in a pentest: We request a database export from a misconfigured backup endpoint, or exploit a basic SQL injection in a search parameter, and observe that the oauth_access_token column contains plaintext values that work against the provider’s API.
The fix: Encrypt tokens at rest using AES-256 with a key stored separately from the database. For providers that support it, use short-lived tokens with refresh token rotation.
2. Tokens returned in API responses unnecessarily
This happens when an API endpoint returns the full user object, including the stored OAuth token, because a developer included it in a serializer without thinking about what the consumer actually needs.
What it looks like in a pentest: We call /api/v1/connections as an authenticated user and observe that the JSON response includes "access_token": "ya29.a0..." alongside the connection metadata. The frontend does not display this field, but it is in the response.
The fix: Audit every API endpoint that touches user integration records. Return only what the client actually needs — typically a status field and a display name, never the raw token.
3. Broken object-level authorization (BOLA) on token-adjacent endpoints
Even if tokens are stored securely, BOLA vulnerabilities allow authenticated users to access other users’ integration objects by manipulating resource IDs.
What it looks like in a pentest: We connect two test accounts. Account A calls GET /api/v1/integrations/847 — its own integration. We then call GET /api/v1/integrations/846 from Account A. If the server returns Account B’s integration record (even without the raw token), we now know which accounts are connected and can potentially trigger actions through them using other endpoints.
The fix: Every API endpoint that returns or acts on an integration object must verify that the requesting user owns that object — not just that the user is authenticated.
4. Token leakage through error messages and logs
Error handling in OAuth flows often includes the token in log messages, error responses, or redirect URLs for debugging purposes. In production, this becomes a persistent exposure.
What it looks like in a pentest: We trigger an error in the OAuth callback flow (by sending a malformed state parameter) and observe that the application logs the full access token in the error output, which is visible in a misconfigured logging endpoint.
The fix: Audit error handling in all OAuth-related routes. Tokens must never appear in log output, error messages, or URLs (including redirect parameters).
5. No token invalidation on account disconnection
When a user disconnects an integration, the token should be revoked at the provider level (via the provider’s revocation endpoint) and deleted from your database. Many implementations delete the database record but skip the provider-side revocation.
What it looks like in a pentest: We connect an integration, capture the token value from a BOLA finding, disconnect the integration, and then use the captured token directly against the provider’s API. The token remains valid.
The fix: Implement provider-side token revocation on disconnect. Most OAuth providers expose a dedicated revocation endpoint (POST /oauth/revoke or similar).
Which SaaS categories carry the most OAuth token risk
Based on the pentests we have run, these product categories consistently show the highest OAuth token risk:
| Category | Connected Accounts | Typical Token Scope |
|---|---|---|
| Social media schedulers | Twitter, LinkedIn, Instagram, Facebook | Post, read DMs, manage pages |
| LinkedIn automation | Full profile, messaging, connections | |
| Email marketing platforms | Gmail, Outlook | Send email, read inbox, manage contacts |
| Sales automation | LinkedIn, Gmail, CRMs | Full CRM access, messaging |
| Analytics platforms | Google Ads, Meta Ads, GA4 | Read ad data, conversion data |
| AI receptionist / phone tools | Google Calendar, Outlook | Calendar read/write, contact access |
If your product is in any of these categories and you have not had a formal security review of your token storage and API authorization layer, you have an unknown risk in production right now.
What a free recon report tells you
A free external recon report does not test your OAuth implementation directly — that requires authenticated access to your API. What it does tell you:
- Whether your API endpoints are visible and enumerable from the outside
- Whether your error responses leak technology details that help an attacker plan their approach
- Whether your subdomains expose staging or dev environments with weaker security controls
- Whether your SSL and security header configuration meets baseline standards
If the recon surfaces gaps at the external layer, the internal OAuth implementation almost certainly has not been reviewed either.
Summary
OAuth-dependent SaaS products carry a unique risk profile: a single application-layer vulnerability can yield credentials not just for your own system but for every external account your customers have connected. The blast radius is disproportionate to the effort required.
The five findings above — plaintext storage, unnecessary token exposure in API responses, BOLA on integration endpoints, token leakage in logs, and missing revocation — are all fixable. None of them require a major architecture change. They all require a deliberate review of the code paths that handle OAuth credentials.
If that review has not happened, it should.