← All posts
May 23, 2026 ยท Security

Live: rotating a leaked OAuth secret in 20 minutes

This morning at 8:47 AM Pacific, our security monitoring flagged that a Google OAuth client secret for SideQuest's Gmail integration had been committed to a public repository. The secret had been live for about 36 hours. Here's what happened next.

8:50 AM. Confirmed the leak. The secret was in a config file that should have been gitignored, and wasn't. The repo was a personal scratchpad for one of our integrations, not a production system, but the secret was real and would let anyone mint tokens for the SideQuest app.

8:54 AM. Generated a new OAuth client secret in Google Cloud Console. Left the old one active for now: we rotate it last, after the new one is confirmed working.

8:58 AM. Updated our claude_desktop_config.json template and our internal credential store with the new secret. Re-ran the Gmail OAuth dance to mint a fresh refresh token.

9:05 AM. Tested end-to-end. Asked Claude to list incoming POs from Gmail and draft a QuickBooks estimate. Both worked. Confirmed the new secret was signing requests by checking the Security alert email Google sent.

9:08 AM. Deleted the old Et8K... secret in Google Cloud Console. Anyone holding a copy of the leaked secret could no longer use it.

9:11 AM. Removed the secret from git history with BFG Repo-Cleaner, then force-pushed. ~90 seconds for a small repo.

9:14 AM. Audited recent activity in the Google Cloud audit log for the SideQuest project. No suspicious access. The leaked secret had been live for 36 hours but nobody had grabbed it.

Total clock time from "I see a leak" to "the leak is closed and verified": 24 minutes.

What made this fast

Pre-built rotation script. We have a finish_rotation.py that handles writing the new secret to the credential store, re-running OAuth, and re-injecting env vars into Claude Desktop config. We wrote it the first time we rotated a secret, six months ago. Every rotation since has used it. Time invested upfront: 90 minutes. Time saved per rotation: 20+ minutes.

The old-secret-stays-active overlap. Google Cloud lets you have two OAuth client secrets active at once. We always create the new one, verify it works, then delete the old one. No window where the system is broken.

What we did badly

The secret was in a public repo at all. Standard practice is to keep secrets in a secret manager (we use 1Password Connect for production). The leak happened because one of us copied a secret into a config file for "five minutes of testing" and never moved it out.

Our pre-commit hook didn't catch it. We have a hook that scans for AWS keys, Stripe keys, and a few other patterns. It didn't have the Google OAuth client-secret pattern. It does now.

The leak was live for 36 hours before we noticed. Our monitoring is set up for credentials in known formats. Google's OAuth client secrets have a less distinctive format. We're moving to GitGuardian for full-repo monitoring this week.

If you're a customer

The new OAuth client is active in your Claude Desktop installation as of today. The leaked secret is dead. Email me directly if you want the audit log dump.

More on our security model: sidequestautomation.com/security.