Vulnerability DatabaseGHSA-wjqm-3pj8-j9vc

GHSA-wjqm-3pj8-j9vc: 
JavaScript vulnerability analysis and mitigation

Summary

OpenNext stores "use cache" entries under a storage key derived from the raw cache key provided by Next.js. That key embeds the serialized arguments of the cached function. The S3 incremental caches (s3, the default, s3-lite, and the S3 part of multi-tier-ddb-s3) and fs-dev build the object key with path.join, which normalizes path segments. As a result, different argument values can map to the same stored entry. An attacker who can pass a string to a "use cache" function can then have their result served to users calling it with another value. With enough ../ segments, the S3 object key also escapes the build ID and the configured CACHE_BUCKET_KEY_PREFIX. s3-lite and multi-tier-ddb-s3 also send the key as a URL path, so the .composable suffix can be escaped too. @opennextjs/cloudflare bundles the same "use cache" handler and is affected through its regional cache and, to a lesser extent, its KV/R2 incremental caches.

Details

For a cached function getPost(slug), the Next.js cache key looks like ["<buildId>","<functionId>",["<slug>"]]. The S3 key is built as:

path.posix.join(CACHE_BUCKET_KEY_PREFIX, BUILD_ID, `${key}.composable`)

path.posix.join collapses //, removes ./ and resolves ../:

ArgumentS3 object key
a/bcache-prefix/BUILD_ID/["BUILD_ID","fnA",["a/b"]].composable
a//bsame
a/./bsame
a/x/../bsame
p/../../../../x (function fnA)../x"]].composable
q/../../../../x (function fnB)same (different function, prefix and build ID dropped)
Request-controlled strings can contain these sequences: search params, or route params containing an encoded %2F. So the first request to compute a value decides what is stored for every argument value that normalizes the same way.
s3-lite and the S3 part of multi-tier-ddb-s3 then send that key as the path of a URL (https://<bucket>.s3.<region>.amazonaws.com/<key>), which transforms it further:
- # truncates the key, and ? starts the query string.
- %XX sequences are decoded.
- \ becomes /.
So the .composable suffix can be escaped and other entry types targeted. For example, the argument p/../index.cache# writes to <prefix>/<buildId>/index.cache, the ISR entry for /.
The raw key is also used as the path in the original-mode tag caches (dynamodb, dynamodb-lite and fs-dev), which build their keys with path.join too.
@opennextjs/cloudflare bundles the @opennextjs/aws "use cache" handler, so it is affected too:
- The regional cache (withRegionalCache) builds a Cache API URL as http://cache.local/<buildId>/<key>.composable, so different arguments can share the same regional cache entry:
- The URL builder collapses // with a replace.
- URL parsing resolves ./ and ../, \ becomes /, and characters are percent-encoded, so a b and a%20b collide.
- The Cache API ignores everything after #.
- The KV and R2 incremental caches store the SHA-256 of the UTF-8 encoded key. UTF-8 encoding replaces lone surrogates with U+FFFD, so keys that differ only by lone surrogates collide. String arguments are JSON-escaped in the key (\ud800). Raw lone surrogates only occur with binary arguments (ArrayBuffer, typed arrays, Blob).
All of these are fixed by the same change: the handler now passes a fixed-format key to every backend.

Impact

An application is affected when all of the following are true:

  1. It uses "use cache" and is deployed with either:
    • @opennextjs/aws with the S3 (s3, the default, or s3-lite) or multi-tier-ddb-s3 incremental cache, or
    • @opennextjs/cloudflare with the regional cache (key normalization) or the KV/R2 incremental cache (lone surrogates in binary arguments only).
  2. A "use cache" function receives a request-controlled string argument that is not validated or encoded, or, for KV/R2, a request-controlled binary argument.
  3. The function's result for an attacker-chosen value differs meaningfully from its result for the normalized value. Examples: a not-found result, content echoing the argument, or data selected by a path-like identifier. Under these conditions, an unauthenticated attacker can poison the cached result served to other users for a different argument value, for example making a valid entry render as not found until it expires or is revalidated. With the S3 incremental caches, the attacker can also write entries outside the configured key prefix and build ID, which persist across deployments. With s3, the written key always ends with the serialized end of the arguments plus .composable, so overwriting an arbitrary existing entry has not been demonstrated. With s3-lite and multi-tier-ddb-s3, the suffix can be escaped (see Details), so an attacker can overwrite existing entries of other types, such as ISR pages. Those entries hold a composable value, so they are read as a miss and regenerated: the impact is integrity and availability, not content injection.

Severity

Medium (CVSS 3.1: 4.8) CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L Attack complexity is rated High because exploitation depends on how the application uses request input as "use cache" arguments.

Patches

The patched version stores "use cache" entries, in both the incremental cache and the tag cache, under the SHA-256 of the exact UTF-16 code units of the Next.js cache key. Every backend receives a fixed-format hex key. Existing "use cache" entries are recomputed once after the upgrade. @opennextjs/cloudflare is fixed by a release that bumps its @opennextjs/aws dependency to the patched version.

Workarounds

Validate request-controlled "use cache" arguments, or encode them before the call so that they cannot contain / (for example lookup(encodeURIComponent(p))), and decode inside the function if needed. This does not cover the lone surrogate collisions on KV/R2 from binary arguments. On @opennextjs/cloudflare, not wrapping the incremental cache with withRegionalCache removes the path normalization (KV/R2 alone are only affected by lone surrogates).


Source: NVD

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-q56w-52fg-7qp7MEDIUM6.5
  • JavaScript logoJavaScript
  • @nkootstra/block-kit
NoYesNov 07, 2026
GHSA-3pg2-h62q-24j6MEDIUM6.5
  • JavaScript logoJavaScript
  • @k2b/ui
NoYesNov 07, 2026
GHSA-rm9j-37wp-mwc3MEDIUMN/A
  • JavaScript logoJavaScript
  • @miltonadina/devops
NoYesNov 07, 2026
GHSA-gwj8-fp64-q94qLOWN/A
  • JavaScript logoJavaScript
  • n8n-mcp
NoYesNov 07, 2026
GHSA-68rj-xv59-f2chLOWN/A
  • JavaScript logoJavaScript
  • n8n-mcp
NoYesNov 07, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management