Skip to main content

Astro Node Integration CVE-2026-41322

MEDIUM
Use of Web Browser Cache Containing Sensitive Information (CWE-525)
2026-04-23 https://github.com/withastro/astro GHSA-c57f-mm3j-27q9
5.3
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
5.3 MEDIUM
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
Low

Lifecycle Timeline

4
Patch released
Apr 24, 2026 - 02:30 nvd
Patch available
Analysis Generated
Apr 23, 2026 - 15:30 vuln.today
Analysis Generated
Apr 23, 2026 - 15:00 vuln.today
CVE Published
Apr 23, 2026 - 14:36 nvd
MEDIUM 5.3

DescriptionGitHub Advisory

Summary

Requesting a static JS/CSS resource from the _astro path with an incorrect or malformed if-match header returns a 500 error with a one-year cache lifetime instead of 412 in some cases. As a result, all subsequent requests to that file - regardless of the if-match header - will be served a 5xx error instead of the file until the cache expires.

Sending an incorrect or malformed if-match header should always return a 412 error without any cache headers, which is not the current behavior.

Affected Versions

  • astro@5.14.1
  • @astrojs/node@9.4.4

Proof of Concept

Run the following command:

curl -s -o /dev/null -D - <host location>/_astro/_slug_.UTbyeVfw.css -H "if-match: xxx"

If a 5xx error is not returned, inspect the resources via the browser's web inspector and select another CSS/JS file to request until a 5xx error is returned. The behavior generally defaults to a 5xx response. Note that all static files are immutable, so the cache must be purged or disabled to reproduce reliably.

A response similar to the following is expected from CloudFront:

HTTP/2 500
content-type: text/html
content-length: 166541
date: Thu, 09 Apr 2026 12:53:08 GMT
last-modified: Wed, 21 Jan 2026 13:40:08 GMT
etag: "a68349e96c2faf8861c330aeb548441a"
x-amz-server-side-encryption: AES256
accept-ranges: bytes
server: AmazonS3
x-cache: Error from cloudfront
via: 1.1 3591be88662e5675a9dc1cc4e0a9c392.cloudfront.net (CloudFront)
x-amz-cf-pop: ZRH55-P2
x-amz-cf-id: Rg--RIYCKcA55GZqZXdvu-VTvpxBFFVzV4LBIcKq5pB_hktcrhYbKg==

The above is not the real server output but the AWS error response triggered when the pods return a 5xx. Below is the output of the same curl command issued directly against a pod in Kubernetes:

❯ curl -s -o /dev/null -D - -H "Host: tagesanzeiger.ch" 127.0.0.1:3333/_astro/InstallPrompt.astro_astro_type_script_index_0_lang.C0M4llHG.js -H "if-match: xxx"

HTTP/1.1 500 Internal Server Error
Cache-Control: public, max-age=31536000, immutable
Accept-Ranges: bytes
Last-Modified: Tue, 07 Apr 2026 07:08:03 GMT
ETag: W/"560-19d66c50c38"
Content-Type: text/javascript; charset=utf-8
Date: Tue, 07 Apr 2026 08:23:54 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked

This demonstrates that the pod itself returns a 5xx error instead of 412. In addition, the response includes a Cache-Control: public, max-age=31536000, immutable header.

Because the testing setup configures if-match as part of the cache key, the exploit no longer affects the production application. Prior to that change, the CDN Point of Presence would become cache-poisoned, and any client visiting the affected pages without cached files through the same PoP would receive broken pages. This was reproduced by creating test URLs and visiting them in a browser only after triggering the exploit. The exploited resources returned 5xx errors instead of the original CSS/JS content, breaking the application.

Details

The findings were analyzed with an LLM, which identified the following file as the likely source: serve-static.ts

js
// Lines 129-153

let forwardError = false;

stream.on('error', (err) => {
    if (forwardError) {
        console.error(err.toString());
        res.writeHead(500);
        res.end('Internal server error');
        return;
    }
    // File not found, forward to the SSR handler
    ssr();
});
stream.on('headers', (_res: ServerResponse) => {
    // assets in dist/_astro are hashed and should get the immutable header
    if (normalizedPathname.startsWith(`/${app.manifest.assetsDir}/`)) {
        // This is the "far future" cache header, used for static files whose name includes their digest hash.
        // 1 year (31,536,000 seconds) is convention.
        // Taken from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#immutable
        _res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
    }
});
stream.on('file', () => {
    forwardError = true;
});
stream.pipe(res);

LLM analysis:

> send handles conditional request headers such as If-Match internally. When a file is found but the precondition fails (ETag mismatch), send: > > 1. Emits file (the file exists) → forwardError = true > 2. Emits headersCache-Control: public, max-age=31536000, immutable is set on res > 3. Emits error with a PreconditionFailedError (status 412) > > However, the error handler does not inspect the error's status code: > > `js > stream.on('error', (err) => { > if (forwardError) { > console.error(err.toString()); > res.writeHead(500); // ← always 500, regardless of the actual error > res.end('Internal server error'); > return; > } > ssr(); > }); > ` > > Because Cache-Control was already set during the headers event, the response is sent as: > > ` > HTTP/1.1 500 Internal Server Error > Cache-Control: public, max-age=31536000, immutable > `

Impact

Cache Poisoning - An attacker can force edge servers to cache an error page instead of the actual content, rendering one or more assets unavailable to legitimate users until the cache expires.

AnalysisAI

Cache poisoning in @astrojs/node versions 9.4.4 and earlier allows unauthenticated remote attackers to poison CDN caches by sending malformed if-match headers to static asset endpoints, causing the server to return 500 errors with immutable one-year cache directives instead of the correct 412 Precondition Failed response. This vulnerability affects all subsequent requests to poisoned assets until the cache expires, breaking application functionality for legitimate users. …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Recon
Send HTTP request with malformed if-match header
Delivery
Server processes as conditional request
Exploit
File found, emit file event
Install
Set immutable Cache-Control header
C2
Emit PreconditionFailedError
Execute
Error handler overwrites status to 500
Impact
Response sent with 500 status and cache headers
Step 8
CDN caches 500 error
Step 9
Legitimate requests receive cached error until expiration

Vulnerability AssessmentAI

Exploitation The vulnerability requires the following conditions: (1) Application must be deployed using @astrojs/node version 9.4.4 or earlier; (2) Application must serve immutable static assets from the _astro directory (default Astro configuration); (3) Attacker must have network access to the application (typically internet-facing); (4) CDN or origin caching must be configured to cache responses based on URL only, without segmenting cache keys by conditional headers such as if-match (this is a common misconfiguration but not universal). … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment This vulnerability presents a moderate real-world risk despite the 5.3 CVSS score. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario An attacker sends a single curl request with a malformed if-match header (e.g., 'if-match: xxx') to any static asset in the _astro directory of an Astro application using the vulnerable Node integration (e.g., curl -H 'if-match: xxx' https://example.com/_astro/style.abc123.css). The server incorrectly returns HTTP 500 Internal Server Error with Cache-Control: public, max-age=31536000, immutable headers. …
Remediation Update @astrojs/node to version 9.4.5 or later, and update Astro to the next patched release following 5.14.1. … Detailed patch versions, workarounds, and compensating controls in full report.

Threat intelligence, references, and detailed analysis are available after sign-in.

CVE-2025-1974 CRITICAL POC
9.8 Mar 25

A critical vulnerability in Kubernetes ingress-nginx controller allows unauthenticated attackers with pod network access

CVE-2026-45321 CRITICAL POC
9.6 May 12

Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio

CVE-2025-1098 HIGH POC
8.8 Mar 25

Kubernetes ingress-nginx contains a configuration injection vulnerability via the mirror-target and mirror-host Ingress

CVE-2025-24514 HIGH POC
8.8 Mar 25

A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-url` Ingres

CVE-2025-1097 HIGH POC
8.8 Mar 25

A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-tls-match-c

CVE-2025-55190 CRITICAL POC
9.9 Sep 04

Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. Rated critical severity (CVSS 9.9), this vulne

CVE-2026-22039 CRITICAL POC
9.9 Jan 27

Kyverno Kubernetes policy engine prior to 1.x has a privilege escalation vulnerability (CVSS 9.9) allowing policy bypass

CVE-2026-25996 CRITICAL POC
9.8 Feb 12

String filter bypass in Inspektor Gadget Kubernetes eBPF tooling before fix. Insufficient string escaping enables filter

CVE-2026-31892 HIGH POC
8.9 Mar 11

Authorization bypass in Argo Workflows (2.9.0 through 4.0.1 and 3.7.x before 3.7.11) lets any user permitted to submit W

CVE-2026-23742 HIGH POC
8.8 Jan 16

Skipper versions before 0.23.0 allow authenticated users with Ingress resource creation privileges to execute arbitrary

CVE-2026-25538 HIGH POC
8.8 Feb 04

Devtron is an open source tool integration platform for Kubernetes. [CVSS 8.8 HIGH]

CVE-2026-22771 HIGH POC
8.8 Jan 12

Credential theft via Lua script execution in Envoy Gateway versions before 1.5.7 and 1.6.2 allows authenticated attacker

Share

CVE-2026-41322 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy