WEBINAR
Stop Pentesting like it’s 2006: 6 Modern Lessons from the GigaOm Radar
WEBINAR
Stop Pentesting like it’s 2006: 6 Modern Lessons from the GigaOm Radar

The Hidden Cost of Client-Side Convenience

Analysis revealed that Keycloak authentication artifacts (Access and ID tokens) are being serialized directly into the Next.js hydration payload. Hydration is a concept that has existed with server-side rendering since the early days of React, serving as a bridge between the server and client by attaching event handlers to the Document Object Model (DOM). The Router embeds a JSON blob in the HTML as a script, and the client runtime reads it as the window’s __NEXT_DATA__. While the primary tokens may reside in secure cookies, this vulnerability creates a redundant, accessible instance of the credentials within the DO. It’s noted that the observed double Base64 encoding is an obfuscation technique rather than a security control and does not effectively mitigate the risk of exposure.

Once tokens are accessible to a page executing JavaScript, any script that runs in that origin can take them: an XSS bug, a compromised dependency, or a third-party tag. Even without an active attacker, tokens in rendered payloads have a tendency to spread into unintended locations: error trackers, session replay & log tools, and debugging artifacts. Princeton researchers showed session-replay scripts can capture and transmit highly sensitive user input at scale, and separately documented third-party scripts piggybacking on “Login with Facebook” page context to pull user data once the site has been granted access.

The vulnerability invalidates the confidentiality integrity of the HttpOnly attribute. Despite the cookie’s restrictive configuration, the sensitive artifact is rendered accessible to the client-side runtime, bypassing the intended isolation between the script execution context and the authentication storage.

A critical distinction for architectural review is that the ID token is an OpenID Connect artifact designed exclusively for proof of authentication. It must not be utilized as an API authorization credential or an application session identifier. The vulnerabilities were assessed as Medium severity (CVSS 6.3 and 6.5), with the potential for critical impact in the presence of chaining vectors such as XSS or shared caching.

OAuth Grew Up. Your Web Stack Might Not Have.

OAuth has also evolved alongside application architecture. Browser applications used to mean a page with some JavaScript. These scripts execute either at page load or in response to a specific user action. Today it can mean a single-page app (SPA), a Server-Side Rendered app that hydrates on the client, server components that run partly on the server and partly in the browser (React Server Components), or frameworks that stream raw HTML over the wire using WebSockets or Server-Sent Events (Ruby on Rails). 

These patterns blur trust boundaries: data meant to stay server-side can be serialized into HTML or bootstrap JSON; code that looks “server-ish” can still execute in a client context; and performance layers (edge caching, logging, session replay) can capture whatever you accidentally emit.

Modern OAuth implementation vulnerabilities predominantly reside in the complex intersection of three distinct security domains often conflated under the umbrella of "auth": authorization (defining access capabilities), authentication (verifying identity assertions), and session integrity (cryptographically binding the authenticated state to a specific client context). 

While the core OAuth protocol is mathematically sound, this convergence creates a high-risk "gray area" where defects arise not from the standard itself, but from the failure to maintain strict isolation between token transport and the stateful mechanisms required to prevent replay, session fixation, or leakage.

OAuth 2.1 (in progress) and RFC 9700 help by removing long-known foot-guns and consolidating what secure implementers already do. But modern stacks still create new ways to leak credentials unless you isolate the callback and keep tokens out of the browser.

JWT Leakage as a Privacy Event

When the exposed artifact is a JSON Web Token (JWT) containing embedded claims rather than an opaque reference handle, the incident escalates from a credential vulnerability to a data privacy breach. These tokens frequently transport stable identifiers; like the sub claim, email addresses, or username; which, upon leaking into telemetry, act as persistent correlation keys across disparate systems like error trackers, CDN logs, and APM traces. Even short-lived tokens can generate unauthorized, long-term personal data stores within infrastructure that lacks appropriate governance, necessitating that JWT exposure be scoped as both a security and compliance failure.

Callback isolation is the highest-leverage control

If you only fix one thing, fix this: use a dedicated callback route that does not load your app, does not load third-party scripts, and does not render a “real page” while OAuth parameters are present.A common convenience choice with external identity providers is to reuse an existing route (often /, /home, or /dashboard) as the redirect target so the browser returns to a familiar page with code and state appended. It works, but it concentrates risk: you are landing the most sensitive moment of the flow on the busiest, most instrumented page in the product.

Attack Pattern

Abnormal completion + URL leak + replay

  1. The attacker forces a sign-in to complete in a way that leaves the credential in the browser URL (a common example is state mismatch handling that stops processing but leaves an error page with the code still visible).
  2. The attacker leaks that URL through a separate client-side weakness: a sloppy postMessage listener, a third-party tag that records URLs, or a monitoring tool that captures page state.
  3. The attacker replays the stolen credential to complete login as the victim.

Break the chain by scrubbing the URL immediately (success and failure), and by treating “any script running in this origin” as a potential credential reader.

Solution 1 (Quick): Scrub the URL Immediately

  • Server-rendered apps: after validating the response (and exchanging the code, if applicable), redirect to a clean URL that contains no OAuth artifacts.
  • SPAs: remove query/fragment parameters before loading the rest of the bundle or any third-party resources (for example, with history.replaceState)

Solution 2 (Strong Guarantees): Use a BFF (Best Friend Forever)

When browser apps need strong session integrity, a Backend-for-Frontend (BFF) is the most robust posture: the browser holds a session cookie, and tokens stay server-side.

A small set of defaults covers most of the risk surface:

  • A dedicated callback route with isolation requirements.
  • A hard rule that tokens must not appear in rendered HTML or telemetry.
  • Governance for third-party scripts (inventory, minimize, and treat them as part of the threat model).
  • An explicit architectural decision for browser apps: tokens in the browser by exception, not by default.

Conclusion

Recommendations from OAuth 2.1 and RFC 9700 help by narrowing the protocol’s sharp edges. The remaining failures are usually deployment failures: credentials drifting into URLs, bootstrap payloads, telemetry, and third-party tooling. Callback isolation, immediate URL scrubbing, and (where needed) a BFF are the practical levers.

References:

Back to Blog
About Cobalt
Cobalt combines talent and technology to provide end-to-end offensive security solutions that enable organizations to remediate risk across a dynamically changing attack surface. As the innovators of Pentest as a Service (PtaaS), Cobalt empowers businesses to optimize their existing resources, access an on-demand community of trusted security experts, expedite remediation cycles, and share real-time updates and progress with internal teams to mitigate future risk. More By Cobalt