Jul 21, 2026·6 min read·7 visits
The @astrojs/netlify adapter fails to escape dots and other regular expression metacharacters in developer-defined image pathnames, generating insecure edge configurations that permit attackers to bypass path-level restrictions on Netlify's Image CDN.
A security vulnerability in @astrojs/netlify allows attackers to bypass remote image path restrictions by leveraging unescaped regular expression metacharacters. The integration adapter fails to sanitize developer-defined pathnames before interpolating them into a configuration JSON file consumed by Netlify's Edge Image CDN. This results in overly permissive matching behavior at the edge routing layer, enabling path-traversal and filter bypasses.
The @astrojs/netlify adapter is an integration for the Astro framework that enables building and deploying server-side rendered (SSR) applications directly onto Netlify. During the build phase, the adapter translates developer-defined remote image patterns (image.remotePatterns from astro.config.mjs) into a deployment configuration file located at .netlify/v1/config.json under the images.remote_images property.
This configuration acts as a whitelist of remote hosts and pathnames authorized to utilize Netlify's Edge Image Content Delivery Network (CDN) for caching and optimization. A vulnerability exists within versions of @astrojs/netlify prior to 8.1.2 where the adapter fails to escape regular expression metacharacters within literal pathnames during configuration translation.
The generated configurations are evaluated directly by Netlify's Image CDN at the edge. The absence of proper escaping results in an overly permissive matching pattern, enabling path-level authorization bypasses and allowing unauthorized image resources to be processed and cached.
The root cause of the vulnerability lies within the remotePatternToRegex() function inside the packages/integrations/netlify/src/index.ts file. When processing the configured pathnames, the logic attempts to construct regular expressions for exact matches or wildcard segments (such as /** or /*).
However, the implementation interpolates raw string variables from the developer configuration straight into the regular expression template without sanitizing special characters. Specifically, regular expression metacharacters like the dot (.) are interpreted by Netlify's edge routing engine as wildcards representing any character except a newline.
Since literal directory pathnames often contain dots (such as API version folders /v1.0/ or specific static files), this omission allows a dot to match alternative arbitrary characters (CWE-116, CWE-185). Additionally, there are no compensating runtime validation checks in place during edge CDN execution. Although Astro implements a strict exact-match verification utility named matchPattern() during standard SSR requests, this layer is completely bypassed when requests are served directly by Netlify's Edge Image CDN.
In vulnerable versions of @astrojs/netlify (prior to 8.1.2), the remotePatternToRegex translation block does not sanitize the input pathname before executing interpolation. The following code block demonstrates the vulnerable implementation:
if (pathname) {
if (pathname.endsWith('/**')) {
// Match any path.
regexStr += `(\\${pathname.replace('/**', '')}.*)`;
}
if (pathname.endsWith('/*')) {
// Match one level of path
regexStr += `(\\${pathname.replace('/*', '')}\\/[^/?#]+)\\/?`;
} else {
// Exact match
regexStr += `(\\${pathname})`;
}
}The patched version introduces an explicit escapeRegex utility function. This utility replaces all standard regex metacharacters, such as dots, asterisks, brackets, and parentheses, with their escaped counterparts before injecting them into the compiled regex. The fixed implementation is shown below:
/**
* Escape regex metacharacters in a literal string so it matches verbatim.
*/
function escapeRegex(literal: string): string {
return literal.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
// ... inside remotePatternToRegex() ...
if (pathname) {
if (pathname.endsWith('/**')) {
// Match any path. Escape the literal prefix so metacharacters
// (e.g. `.`) match verbatim instead of acting as wildcards.
regexStr += `(${escapeRegex(pathname.replace('/**', ''))}.*)`;
} else if (pathname.endsWith('/*')) {
// Match one level of path
regexStr += `(${escapeRegex(pathname.replace('/*', ''))}\\/[^/?#]+)\\/?`;
} else {
// Exact match
regexStr += `(${escapeRegex(pathname)})`;
}
}The fix is complete and robust because it maps all key special characters to safe literal representations. It preserves Astro's specific wildcard syntax (/** and /*) by parsing them first, and escaping only the static portion of the user-provided path. This prevents any secondary variant exploits against the path resolution mechanism.
Exploitation of this vulnerability requires a target application to deploy @astrojs/netlify with a remote image configuration containing dot characters in its pathname. Consider an astro.config.mjs setup whitelisting a specific versioned resource path:
// astro.config.mjs
image: {
remotePatterns: [{
protocol: 'https',
hostname: 'cdn.example.com',
pathname: '/img/v1.0/file',
}],
}When processed by a vulnerable adapter, this translates to the pattern https://cdn\\.example\\.com(:[0-9]+)?(\\/img/v1.0/file)([?][^#]*)?$ in .netlify/v1/config.json. Because the dot in v1.0 remains unescaped, an attacker can construct malicious requests to match alternative paths. For instance, the URL https://cdn.example.com/img/v1A0/file will be successfully matched as the dot evaluates 'A' as valid.
More critically, the unescaped dot matches a forward slash (/), allowing path traversal and directory crossing. An attacker requesting https://cdn.example.com/img/v1/0/file bypasses the intended directory restriction. This lets attackers load and optimize assets from unauthorized directories on the allowed host, manipulating the Edge Image CDN directly.
The security impact is classified as Low with a CVSS score of 3.7. The primary consequence is unauthorized resource consumption and filter bypass. Attackers can leverage the flawed regex to force Netlify's Edge Image CDN to retrieve, optimize, and cache arbitrary images from non-permitted paths on the target hostname.
While this does not lead directly to Remote Code Execution (RCE) or sensitive database disclosure, it enables attackers to hijack Netlify cloud resources (Resource Hijacking, MITRE ATT&CK T1496). This can lead to increased CDN operational bandwidth, unexpected serverless usage costs, and potential cache poisoning if malicious payloads are served via the optimized paths.
The vulnerability is not listed in the CISA KEV catalog, and there is no known active exploitation in the wild. Exploitation complexity is high because it requires specific target configurations containing metacharacter-adjacent structures on the whitelisted servers.
To remediate this vulnerability, developers must upgrade the @astrojs/netlify dependency to version 8.1.2 or higher. This updates the underlying configuration compiler to include the safe regex escaping mechanism.
Deployments can be verified by executing a local build via npm run build and auditing the output of .netlify/v1/config.json. Check the images.remote_images field to confirm that all dot characters in configured paths are escaped as \.. For example, a secure output should resemble (\\/img/v1\\.0\\/file) instead of (\\/img/v1.0/file).
If immediate dependency updates are not possible, developers should temporarily remove any regex metacharacters (including dots) from the pathname configurations in astro.config.mjs. Replacing file extensions or version strings with generic directory paths can mitigate direct path traversal risks.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
@astrojs/netlify Astro | < 8.1.2 | 8.1.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-185: Incorrect Regular Expression / CWE-116: Improper Output Escaping |
| Attack Vector | Network |
| CVSS v3.1 Score | 3.7 (Low) |
| EPSS Score | Not Available |
| Impact | Filter Bypass / Resource Hijacking |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
The software does not properly escape metacharacters before incorporating user input into a regular expression, enabling unexpected matching behavior.
A heap out-of-bounds write vulnerability exists in Pillow prior to version 12.3.0 due to an integer overflow during image expansion calculations. The subsequent patch introduced a division-by-zero regression causing denial of service.
CVE-2026-59198 is a high-severity heap out-of-bounds read vulnerability in Pillow, the Python imaging library, affecting versions from 5.2.0 up to 12.3.0. The vulnerability occurs in the TGA RLE compression path due to a calculation mismatch between the allocated packed 1-bit row buffer and the byte-level pixel stride assumption in the C-level encoder. This mismatch allows an attacker to leak up to approximately 57 KB of adjacent process heap memory directly into generated TGA image files.
A critical signed 32-bit integer overflow vulnerability was identified in Pillow (Python Imaging Library) versions prior to 12.3.0. The vulnerability resides within the native C extension library (libImaging) during coordinate and bounding box calculations in functions like ImagingPaste and ImagingFill2. Exploitation can bypass bounds and clipping safety checks, leading to a controlled heap backward underwrite and application crash.
CVE-2026-59200 is a high-severity uncontrolled resource consumption vulnerability in the Pillow Python Imaging Library. The flaw resides in the PDF stream decoder, allowing remote, unauthenticated attackers to trigger host out-of-memory crashes by submitting malicious PDF decompression bombs.
A denial-of-service (DoS) vulnerability in Pillow (Python Imaging Library) versions 12.0.0 through 12.2.0 allows unauthenticated remote attackers to trigger 100% CPU utilization and hang the processing thread. The issue occurs within the Encapsulated PostScript (EPS) image parser (PIL/EpsImagePlugin.py) due to missing validation on the byte count parsed from %%BeginBinary: comments, allowing negative values to cause an infinite backward stream seek loop. This formatting-level state-looping issue occurs during the initial format sniffing phase inside Image.open() and does not require the system Ghostscript interpreter to be executed or present. It is resolved in version 12.3.0.
A Denial of Service vulnerability exists in the JPEG2000 decoder of Pillow (versions 8.2.0 to 12.2.0) due to memory allocation state accumulation across tiles, leading to rapid process termination.