On 13 June 2026 a market intelligence vendor called Klue deactivated the OAuth credentials of every customer it had. The day before, it had found an intruder inside the infrastructure that runs its integrations. The tokens that let Klue read its customers' CRM data had been harvested, and killing all of them was the only move left (The Hacker News, BankInfoSecurity).
This is written for the CTO or founding engineer of a 10 to 40 person product company whose software connects to something the customer owns: their CRM, their Google Drive, their Slack, their GitHub, their accounting system. If one of your tables has a column full of refresh tokens, you are the subject of this post. You are not a bystander to an incident like Klue. You are the vendor in it.
Almost all the coverage was written for the customer side: audit your connected apps, review third party access. That advice is correct and it is not yours. Your version is harder and hardly anyone writes it down. You are holding other companies' credentials at scale, and the failure that ends you is not someone guessing a password on your login page. It is someone reaching your token store and leaving with the authority of every customer you have.
What actually happened, twice
Klue detected anomalous activity on 12 June 2026 and deactivated OAuth credentials for all customers the following day, temporarily disabling integrations with Salesforce, HubSpot, SharePoint, Zoom, Gong, Chorus, Clari, Google Drive and Slack. Salesforce disabled the Klue integration on its side. Reporting names Huntress, Recorded Future, Tanium and Jamf among the affected organisations, attributes the intrusion to a group tracked as Icarus, and traces initial access to a compromised legacy credential tied to an integration tool rather than to any flaw in OAuth itself (Infosecurity Magazine, The Hacker News).
This was the second run of the same play in ten months. In August 2025, an actor tracked as UNC6395 used OAuth tokens belonging to the Salesloft Drift integration to query and export Salesforce data from more than 700 organisations over roughly ten days, before Salesforce and Salesloft disabled the Drift integrations on 20 August 2025 (Unit 42, Cloud Security Alliance).
Two vendors, two intrusions that never touched a customer's perimeter, and in both cases the asset stolen was a pile of credentials the vendor held on someone else's behalf. Practitioner opinion: if you sell an integration, that pile is now the most valuable thing in your estate, and most teams still classify it as application data.
1. Your token store is a vault, and it is probably a database column
Start by naming the asset. Write down the exact table and column where refresh tokens live, which services and which humans can read it, and what a full dump would let an attacker do. Most teams doing this for the first time find the tokens sitting in the same Postgres instance as everything else, readable by the same application role that serves the API, with the encryption key in the same environment file.
The reason is not carelessness. The token arrived through a feature ticket: someone shipped the Slack integration, the token needed somewhere to live, and the schema grew a column. Nobody ever held a design review that said "we are now a custodian of other companies' production credentials".
The practical output of this step is a one page inventory: every provider you integrate with, the scopes you request from each, how many live grants you hold, the oldest grant still in use, and who signs off on adding a new scope. Both incidents above were resolved by mass revocation. If you cannot produce that inventory today, you cannot run the response either.
2. A refresh token has no natural death
Access tokens expire in minutes or hours, which is what makes people relaxed about them. Refresh tokens are the ones that matter, because they are what turns a single moment of theft into standing access. Salesforce documents the behaviour plainly: the refresh token is used indefinitely unless revoked by the user or an administrator, and the refresh token policy is evaluated only when the refresh token is used, not against a live session (Salesforce Help).
Read that as an attacker would. A refresh token exfiltrated today keeps minting valid access tokens tomorrow, next month and next year, and it does so through the front door of the API, from any network, with no second factor.
Two things follow. First, the useful lifetime metric is not your access token TTL, it is the age of your oldest live grant. Query it. Second, the provider usually gives you a shorter leash than you are using: Salesforce exposes refresh token policies including immediate expiry, and most large providers offer something similar. Take the tighter policy, and treat any grant older than your longest customer contract as a finding rather than history.
3. Scope is blast radius, and you asked for too much
The Drift case is the clearest lesson available on scope. A chatbot integration held access to Salesforce data far wider than a chatbot needs, and because that integration authorised per user, the attacker inherited whatever each authorising user could see. Where an administrator had connected the app, the attacker got administrator reach (Permiso).
The uncomfortable part is that over scoping is usually your fault as the vendor, not the customer's. Broad scopes make onboarding smooth. Nobody has to come back and re request consent when you ship a feature. Every one of those is a real benefit, and each is paid for in blast radius that only shows up on the worst day.
The fix is unglamorous and it works. List every scope you request, and next to it the specific feature that requires it. Any scope without a named feature gets dropped at the next release. Split write scopes from read and request write only for integrations that write. Where a provider supports incremental consent, use it. Practitioner opinion: a second consent prompt costs you a support ticket, an unnecessary write scope costs you the incident.
4. Both intrusions started at a developer credential
Neither of these attacks began with OAuth. They began in engineering infrastructure. In the Salesloft case the actor accessed GitHub repositories over a period of months before pivoting into the environment holding the tokens (Unit 42). Reporting on Klue traces initial access to a compromised credential tied to an integration tool, described in several accounts as a GitHub personal access token (BankInfoSecurity).
This is the part a small team can genuinely fix this quarter, because the controls are free and documented. GitHub's own documentation describes a maximum lifetime policy for fine grained personal access tokens at organisation and enterprise level with a 366 day ceiling, and automatic deletion of any token unused for twelve months (GitHub Docs). Organisation owners can review and revoke the tokens that have access to their resources from a single screen (GitHub Docs).
Do three things. Enforce a maximum token lifetime at the organisation level so long lived tokens cannot be created quietly. Replace classic tokens with fine grained ones scoped to single repositories. Turn on secret scanning with push protection. The takeaway is that your OAuth posture is bounded by your CI posture, and the second is where both of these stories actually started.
5. Encrypt so one stolen key is not every customer
Encrypting the token column is table stakes, and the control most often implemented in a way that buys nothing. If the application process that reads the tokens also holds the key, an attacker who reaches that process gets both, and you have bought yourself protection against a stolen disk snapshot and nothing else.
The architecture worth building is envelope encryption with the key in a managed KMS: a data key per tenant, wrapped by a master key that never leaves the KMS, with decrypt calls made under a narrow role. AWS, Google Cloud and Azure all document this pattern and all three log every decrypt, which is the property that matters here (AWS KMS documentation, Google Cloud KMS documentation).
Per tenant keys are worth the effort for one specific reason beyond blast radius. They make cryptographic deletion possible: when a customer leaves, you destroy their key and their tokens become unreadable without touching a row. They also give you a detection signal: a decrypt volume graph per tenant is flat and boring until the day it is not. Take the takeaway that encryption is a detection control here as much as a confidentiality one.
6. Stop issuing bearer tokens you cannot bind
An OAuth access token is a bearer token by default, which the specification states directly: any party in possession of it can use it (RFC 6750). Theft equals use, with no further step required.
The IETF published its consolidated guidance as RFC 9700, Best Current Practice for OAuth 2.0 Security, in January 2025. Two of its requirements are directly relevant. Refresh tokens for public clients must be sender constrained or must use refresh token rotation, where every refresh issues a new refresh token and invalidates the previous one. And authorisation servers should support sender constraining access tokens through mutual TLS or Demonstrating Proof of Possession, so that a stolen token is useless without the client's key (RFC 9700, RFC 9449, RFC 8705).
As the client rather than the provider you take what the provider supports, and today many offer neither DPoP nor mutual TLS. One thing stays fully in your hands: implement rotation wherever it is available, and treat reuse of an already rotated refresh token as an alarm rather than a retry, because a replayed old token is one of the few clean signals that a copy exists somewhere you did not put it.
7. Revocation you have actually pulled
RFC 7009 defines the revocation endpoint, and its behaviour is the useful part: revoking a token invalidates it and, where applicable, other tokens issued under the same authorisation grant (RFC 7009). Klue's response on 13 June was exactly this, executed across an entire customer base in a day.
Ask the honest question. If you learned in the next hour that your token store had been copied, could you revoke every grant you hold, and how long would it take? Most teams have never run it. The code path exists, written once during the integration, and exercised only when a single customer disconnected.
Build the drill and schedule it. You need a documented mass revocation procedure per provider, a script that walks your grants and calls the revocation endpoint within the provider's rate limits, a tested reconnection flow so customers can re authorise without a support call, and a quarterly rehearsal on a real grant in staging. Note one limit: revocation stops the authorisation server issuing new tokens, but a self contained JWT access token can stay valid at a resource server until it expires, so your worst case window is the access token lifetime.
8. Watch the integration, not just the login
Delegated access is a monitoring blind spot in almost every product. Human logins get rate limits, anomaly detection and alerts. The integration that pulls customer data all day gets a dashboard of success rates. In the Drift case the attacker ran queries against customer orgs for roughly ten days before the integration was disabled (Unit 42).
You hold a signal the provider does not: you know what your own product is supposed to do with each grant. Your sync runs on a schedule, touches a predictable set of objects and moves a predictable volume. Anything outside that shape is a bug or someone else, which makes it a sharper detector than anything the provider can build without knowing your application.
Alert on the specific shapes. A refresh from an IP range that is not your egress. Token use outside your scheduled windows. Object types your product never reads. Row volumes far above the tenant's normal. Log every token use with tenant, source and scope so the timeline exists before you need it. Egress IP pinning alone is worth building early: it is cheap, and it makes a stolen token far less useful outside your infrastructure.
9. The email you will have to send in the first six hours
An incident like this becomes a communications event within hours, and every affected customer asks the same three questions: was my data touched, what have you already done, and what do I need to do. Klue's public timeline, detection to mass deactivation inside two days, is the shape of a good answer.
Draft the template now, while nothing is on fire. It needs the window of exposure with times, which grants were affected and which were not, confirmation that credentials were already revoked before the customer was told, and the exact steps to run on their side. The engineering work that makes this letter possible is the per tenant usage log from the previous section. Without it every sentence becomes "we cannot rule out", which is the phrase that turns a security incident into a churn event. Practitioner opinion: being able to tell one customer they were untouched is worth more than most detection tooling, and it comes from logging you can add in an afternoon.
10. The platform is moving under you
Providers are tightening the integration surface, and the changes land on vendors first. Salesforce restricted the creation of new connected apps as of the Spring '26 release and now directs developers to external client apps instead, with existing connected apps continuing to work and migration tooling provided (Salesforce Developers). Treat that as the pattern rather than a one off: provider side controls over third party access keep moving toward shorter lifetimes, narrower default scopes, admin visibility over which apps hold which grants, and faster kill switches. Every one is good for the ecosystem and every one is a migration ticket for you, usually with a deadline set by someone else.
Put the practical version in your engineering calendar. Subscribe to the release notes for every provider you integrate with, keep a page listing which auth mechanism each integration uses and when it was last reviewed, and budget one integration migration a year as normal maintenance. The takeaway is that an integration is not a shipped feature, it is a running dependency on someone else's security roadmap.
The controls, ranked by what they cost you
| Control | What it limits | Effort |
| Scope inventory and pruning | How much an attacker can reach per grant | Days, no provider dependency |
| Enforced short lifetimes on CI and developer tokens | The path attackers actually used | Hours, configuration only |
| Per tenant token usage logging | Time to detect, and what you can tell each customer | Days |
| Egress IP pinning for provider APIs | Usefulness of a token outside your estate | Days |
| Envelope encryption with per tenant keys | Value of a database dump | Weeks |
| Refresh token rotation with reuse alerting | Standing access, and silent copies | Weeks, provider dependent |
| Tested mass revocation drill | How long the worst day lasts | Weeks, then quarterly |
| Sender constrained tokens, DPoP or mutual TLS | Whether theft equals use at all | Provider dependent |
What to do at your stage
Pre-seed, first integrations shipping. Do the scope inventory before you have many grants, because pruning a scope later means re consent from every customer you already onboarded. Put tokens behind a managed KMS key from the first commit and enforce token lifetime policies in GitHub. That is a week of work, and the cheapest week you will ever spend on this.
Seed, dozens of customers, integrations in the sales pitch. Add per tenant usage logging and egress pinning, then write and rehearse the mass revocation drill. This is also where security questionnaires start asking how you store third party credentials, so the work pays twice: risk reduction and sales velocity.
Series A, integrations are the product. Move to per tenant data keys, rotation with reuse alerting, and anomaly detection on your own sync traffic. Give each provider relationship a named owner who tracks release notes and deprecations. At this size an integration outage is a revenue event, so the migration budget is easier to justify than the security one. Ask for both in the same ticket.
Where to start this week
Pick one query and run it today: the age of your oldest live refresh token. If the answer is older than your last security review, you have found your starting point, and every control above becomes concrete rather than theoretical. Then write the inventory, one page, one row per provider.
The cloud and security checklist on this site walks the same ground for a lean team, including the token handling and revocation items. You can open it here: the MatrixGard cloud and security checklist. It is free, it takes about twenty minutes, and it will tell you which of the eight controls above you already have.
About the author
Avinash S is the founder of MatrixGard, a fractional DevSecOps practice for early-stage startups, funded or bootstrapped. MatrixGard acts as the cloud, infrastructure and security team for companies that are not yet ready to hire one, covering cloud architecture, cost control, and the security posture that enterprise customers ask about before they sign.
Methodology
Every incident detail in this post comes from public reporting or vendor statements published at the time, and every specification claim comes from the primary IETF document or the provider's own documentation, both linked inline. Where accounts differ across outlets, the wording follows the more conservative one. Nothing is drawn from client work and no figures are estimated. Judgement calls that are not documented anywhere are labelled practitioner opinion. Both incidents referenced, Salesloft Drift in August 2025 and Klue in June 2026, are documented in detail by multiple independent sources.