deniz.in

Markets

Weather

Loading weather

· via Hacker News – Front Page (native)

Google's leaked OAuth secret doubled as a signing key, enabling RCE across developer sites

A researcher found that the OAuth client secret inside Google's shared DevSite session cookie was also the Flask signing key, allowing forged cookies and unauthenticated remote code execution on Google's servers.

Google's leaked OAuth secret doubled as a signing key, enabling RCE across developer sites

A security researcher has earned a $90,000 bounty from Google after showing that a shared OAuth endpoint on Google's developer sites could be abused for unauthenticated remote code execution.

The finding, detailed in a writeup hosted at simonkoeck.com and surfaced on Hacker News' front page, targeted the OAuth sign-in flow that Google's developer documentation sites share. According to the writeup's timeline, Google triaged the report within a day of its submission on August 6, 2026, fixed the issue on October 7, and awarded $75,000 — the base payout for an S0-severity RCE in the tier Google labels Normal Google Applications — increased by 20% for report quality.

An oversized session cookie

The work began with the /oauth2authorize endpoint on developers.google.com, which sets a Flask session cookie and redirects to Google's sign-in page without requiring an account. The cookie drew attention because, at roughly 1,200 bytes, it was far larger than a CSRF token and a return URL require.

Flask signs session cookies rather than encrypting them, so the contents are readable to anyone who receives one. After decompressing the payload, the researcher found a JSON session object containing a base64-encoded pickle, which disassembled into an OAuth2WebServerFlow object complete with Google's OAuth client_id and client_secret. The writeup notes the secret was live at the time of writing, though it is redacted in the published version.

The secret that signed itself

A client secret travelling in a cookie is a finding by itself, but the researcher observed something worse: the same value verified the cookie's signature, meaning the Flask signing key was embedded in the very object it was used to sign.

To confirm this was not coincidence, the researcher recomputed the expected signature offline using Flask's itsdangerous cookie-session key derivation and produced a byte-for-byte match. Altering one character of the signature caused rejection, while re-signing the original payload with the recovered secret was accepted. With the key known, every key and value in the session could be forged while still producing a signature the server would honour.

From forged cookie to code execution

Code execution followed from how the OAuth callback handles the session: it reads the flow entry back out, base64-decodes it and passes the bytes to pickle.loads. Pickle is only safe in this position while nobody else can forge a valid cookie, an assumption that collapses once the signing key is public. A pickle REDUCE opcode names a callable and its arguments, and unpickling invokes it.

Because the attacker also controls the CSRF token and the flow key name, nothing on the server needs to line up. Rather than run commands on Google's production systems, the researcher proved execution through timing: payloads that reduced to time.sleep(N) delayed responses by exactly the chosen number of seconds, while control requests — no cookie, a tampered signature, or a valid signature without a matching flow entry — all failed cleanly.

Not one site, but a platform

developers.google.com sits on the shared DevSite platform, so the recovered key also signed valid sessions for firebase.google.com, developer.android.com, source.android.com and docs.partner.android.com, according to the writeup.

The fix required four stacked changes: rotate the exposed OAuth client secrets and invalidate all sessions signed with them; give each deployment its own high-entropy Flask secret held in a server-side store; keep the OAuth flow object on the server so cookies carry only an opaque reference; and replace pickle with a schema-checked, data-only format for anything crossing a client boundary. Breaking any single link would have stopped the attack.

Why it matters

The chain is a study in layered failures: an oversized cookie, a secret doing double duty, and a dangerous deserializer each looked survivable in isolation, yet together they yielded unauthenticated code execution that the researcher says needed only two GET requests. It also shows how shared platforms amplify blast radius, since one key compromise covered five Google domains. For developers, the lessons are concrete: never sign a cookie with a key stored inside it, never deserialize pickled data that a client can influence, and treat server-side session state as the default rather than the fallback.

  • #security
  • #google
  • #oauth
  • #flask
  • #bug-bounty

Related posts