Skip to main content
Vulnerability Database/CVE-2024-23841

CVE-2024-23841: Apollo Client Next.js XSS Vulnerability

CVE-2024-23841 is a cross-site scripting flaw in Apollo Client Next.js that enables attackers to inject malicious scripts through crafted links or compromised GraphQL responses. This article covers technical details, affected versions, security impact, and how to mitigate the risk.

Published:

CVE-2024-23841 Overview

CVE-2024-23841 is a cross-site scripting (XSS) vulnerability in the @apollo/experimental-apollo-client-nextjs NPM package, which provides Apollo Client support for the Next.js App Router. The package fails to properly escape data embedded in server-side rendered (SSR) HTML output, allowing attackers to inject executable script into the rendered page [CWE-80]. Exploitation requires an attacker to introduce malicious input through a crafted link or by persisting hostile payloads in a GraphQL data source that the client later renders. The maintainers resolved the issue in version 0.7.0 by escaping JSON strings embedded in HTML transport payloads.

Critical Impact

Successful exploitation lets an attacker execute arbitrary JavaScript in the context of the victim's browser session, enabling session theft, UI manipulation, or redirection to attacker-controlled destinations.

Affected Products

  • @apollo/experimental-apollo-client-nextjs versions prior to 0.7.0
  • Apollo Client integrations using the Next.js App Router SSR data transport
  • Node.js runtime deployments of the vulnerable package

Discovery Timeline

  • 2024-01-30 - CVE-2024-23841 published to NVD
  • 2026-06-17 - Last updated in NVD database

Technical Details for CVE-2024-23841

Vulnerability Analysis

The @apollo/experimental-apollo-client-nextjs package serializes Apollo Client cache data into HTML during server-side rendering so the browser can hydrate it on the client. Before version 0.7.0, the SSR data transport layer embedded GraphQL response data as JSON directly inside <script> tags without escaping HTML-significant characters. An attacker who controls any field returned by the GraphQL server, or who can influence query variables through a crafted link, can inject a </script> sequence followed by arbitrary JavaScript.

Because the injected payload executes in the application's origin, it inherits access to cookies, local storage, and authenticated API endpoints. The attack requires user interaction, typically clicking a malicious link, but no authentication is needed.

Root Cause

The dataTransport.ts module serialized Apollo Client state using JSON.stringify and inlined the result into the HTML stream. JSON serialization alone does not neutralize the <, >, and & characters, nor the Unicode line separators U+2028 and U+2029, which are valid in JSON but can terminate a script context or break JavaScript parsing. This gap allowed GraphQL response fields or query inputs to escape the surrounding <script> element.

Attack Vector

An attacker either persists a malicious value in a GraphQL-backed data store or crafts a URL whose query parameters flow into a GraphQL query executed during SSR. When a victim loads the page, the server renders the poisoned data into HTML. The browser then parses the injected markup and executes the attacker's script.

typescript
// Patch: package/src/util/htmlescape.ts
// Introduced in version 0.7.0 to escape HTML-sensitive characters
// in JSON embedded within <script> tags.

const ESCAPE_LOOKUP: { [match: string]: string } = {
  "&": "\\\u0026",
  ">": "\\\u003e",
  "<": "\\\u003c",
  "\\u2028": "\\\u2028",
  "\\u2029": "\\\u2029",
};

export const ESCAPE_REGEX = /[&><\\u2028\\u2029]/g;

export function htmlEscapeJsonString(str: string): string {
  return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
}

Source: GitHub Commit b92bc42

Detection Methods for CVE-2024-23841

Indicators of Compromise

  • SSR HTML responses containing unescaped </script> sequences inside Apollo state hydration blocks
  • GraphQL responses containing characters such as <, >, or Unicode line separators U+2028 / U+2029 in string fields rendered server-side
  • Unexpected outbound requests from client browsers immediately after page load, indicating injected script execution

Detection Strategies

  • Audit the installed version of @apollo/experimental-apollo-client-nextjs across package manifests and lockfiles; any version below 0.7.0 is vulnerable
  • Inspect server-rendered HTML for Apollo cache payloads to confirm JSON fields are escaped using \\u003c, \\u003e, and \\u0026 sequences
  • Review GraphQL query logs for inputs containing HTML tags, event handlers, or javascript: URIs that could flow into SSR output

Monitoring Recommendations

  • Enable a strict Content Security Policy (CSP) and alert on script-src violations reported from production Next.js origins
  • Monitor web application firewall logs for query parameters containing <script>, onerror=, or encoded script fragments targeting Apollo-backed routes
  • Track dependency updates in CI/CD pipelines and fail builds that resolve vulnerable Apollo Client Next.js versions

How to Mitigate CVE-2024-23841

Immediate Actions Required

  • Upgrade @apollo/experimental-apollo-client-nextjs to version 0.7.0 or later across all Next.js projects
  • Rebuild and redeploy affected applications after the dependency update to replace cached SSR bundles
  • Rotate session tokens if logs indicate requests carrying script payloads reached vulnerable endpoints

Patch Information

The fix was committed in GitHub commit b92bc42abd5f8e17d4db361c36bd08e4f541a46b and documented in GitHub Security Advisory GHSA-rv8p-rr2h-fgpg. The patch introduces an htmlEscapeJsonString helper that escapes &, <, >, U+2028, and U+2029 in JSON serialized into HTML.

Workarounds

  • Validate and sanitize all GraphQL query variables derived from user-controlled URLs or form inputs
  • Apply server-side output filters that reject GraphQL responses containing raw HTML control characters in string fields
  • Deploy a Content Security Policy that disallows inline scripts without a nonce, reducing the impact of injected <script> content
bash
# Upgrade the vulnerable package to the patched release
npm install @apollo/experimental-nextjs-app-support@^0.7.0

# Verify the installed version
npm ls @apollo/experimental-nextjs-app-support

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.