Feb 15, 2026·7 min read·155 visits
BusyBox `wget` (<= 1.37.0) doesn't strip control characters from URLs. If an attacker controls the URL passed to `wget`, they can inject `\r\n` sequences to manipulate the HTTP request headers. This allows for HTTP Request Splitting, potentially poisoning caches or injecting malicious headers like `Authorization` or `X-Forwarded-For`.
BusyBox, the undisputed 'Swiss Army Knife of Embedded Linux,' has a jagged edge in its `wget` implementation. Through version 1.37.0, the utility fails to properly sanitize URL inputs, specifically allowing Carriage Return (CR) and Line Feed (LF) characters to pass through to the raw HTTP request line. This vulnerability, discovered by researcher Takeuchi Yuma, opens the door to HTTP Request Splitting and CRLF Injection. In environments where `wget` processes untrusted URLs—such as webhooks, CI/CD pipelines, or containerized automated tasks—attackers can inject arbitrary HTTP headers, potentially leading to cache poisoning, request smuggling, or internal security control bypasses.
If you have ever touched a router, an IoT toaster, or a minimal Docker container, you have used BusyBox. It is the minimalist's dream: a single binary that masquerades as hundreds of standard Unix utilities. It is efficient, it is everywhere, and it is usually running as root in places you cannot easily patch. One of its most critical applets is wget, a tool used universally to fetch files, health-check services, and download initialization scripts.
The problem with minimalism is that sometimes safety checks are viewed as 'bloat.' In the world of high-level languages like Python or Go, HTTP libraries protect you from yourself. They refuse to put a newline character in a header because they know it violates the protocol. BusyBox, however, is written in C. It talks to the network using raw sockets and optimism. It assumes that if you give it a URL, that URL is a valid string of characters that won't break the HTTP protocol.
CVE-2025-60876 serves as a harsh reminder that the HTTP protocol is, at its core, just text sent over a wire. If you can control that text, you control the conversation. By failing to scrub 'control characters'—specifically the Carriage Return (\r, 0x0D) and Line Feed (\n, 0x0A)—BusyBox wget allows an attacker to break out of the URL path and start writing their own HTTP headers. This isn't a memory corruption bug; it's a logic flaw where the program blindly trusts that a string is just a string, not a command delimiter.
To understand why this is dangerous, you have to look at how a raw HTTP request is constructed. When you run wget http://example.com/file, the program opens a socket to port 80 and sends a formatted string. It looks something like this:
GET /file HTTP/1.1
Host: example.com
User-Agent: Wget
Connection: close
The structure relies entirely on newlines (\r\n) to separate the request line from the headers, and the headers from the body. The vulnerability lies in networking/wget.c. The code takes the path component of the URL and sprintfs it directly into that first line. It does not check if the path contains the very characters used to delimit the protocol.
If an attacker provides a URL like http://example.com/file%0d%0aX-Evil: true, and the shell or a calling script decodes that before passing it to wget (or if wget processes a redirect containing it), the resulting raw request sent to the server becomes:
GET /file
X-Evil: true HTTP/1.1
Host: example.com
...The server parses this. It sees a GET request for /file. Then, crucially, it sees a header named X-Evil with a value of true HTTP/1.1. Wait, that looks broken, doesn't it? The server might ignore the garbage trailing the header, or worse, if the attacker aligns the injection perfectly, they can completely fabricate a second request (Request Splitting) or inject critical headers that the backend application uses for authentication.
Let's look at the smoking gun. In the vulnerable versions of BusyBox, the code responsible for parsing the URL and preparing the request didn't care about the content of the string. It was a simple string manipulation operation. The fix, introduced in response to this CVE, is telling. It adds a dedicated sanitization function.
Here is the essence of the fix introduced in networking/wget.c. The developers had to explicitly teach wget what a 'bad' byte looks like:
static void die_on_bad_http_bytes(const char *s, int reject_space, const char *what)
{
const unsigned char *p = (const unsigned char*)s;
while (*p) {
unsigned char c = *p++;
// The Blocklist: CR, LF, Control Chars, DEL, and optionally Space
if (c == '\r' || c == '\n' || c < 0x20 || c == 0x7f || (reject_space && c == ' '))
bb_error_msg_and_die("bad %s", what);
}
}Before this function existed, wget would happily process a URL containing 0x0D (\r) and 0x0A (\n). Now, it iterates through the target.path and target.host byte by byte. If it sees a control character (anything below 0x20), it calls bb_error_msg_and_die.
Notice the reject_space argument? The vulnerability wasn't just CRLF. It was also raw spaces. In HTTP/1.1, the request line is METHOD URI VERSION. If you inject a space into the URI, you can prematurely terminate the URI field and confuse the server into thinking the protocol version comes next. This patch slams the door on both techniques.
How do we weaponize this? We need a scenario where we control the URL. Imagine a microservice that downloads images based on a user-supplied URL. It runs a command like busybox wget $USER_INPUT -O -. If the application doesn't strictly validate the URL format before shelling out (and let's be honest, they rarely do), we are in business.
We can verify this with a simple Python server that checks for a secret header, X-Secret. If the header is present, it gives us the flag. If not, it gives us a 403.
# The Victim Server Logic
if self.headers.get("X-Secret") == "yes":
return "Here are the nuclear codes"
else:
return "Access Denied"The attack payload looks like this:
http://127.0.0.1:9000/funny_cat.jpg HTTP/1.1 X-Secret: yes a:
When wget receives this (assuming the shell passes the raw bytes), it constructs the request. The injection splits the request line. The a: at the end is a classic trick to consume the legitimate HTTP/1.1 that wget automatically appends, turning it into a garbage header a: HTTP/1.1.
The Resulting Wire Traffic:
GET /funny_cat.jpg HTTP/1.1
X-Secret: yes
a: HTTP/1.1
Host: 127.0.0.1:9000
User-Agent: Wget
...The server sees the X-Secret header, validates it, and hands over the goods. We have successfully bypassed the application logic by manipulating the transport layer.
You might be thinking, 'So I can inject headers, big deal.' But in the modern cloud landscape, headers are identity.
1. SSRF on Steroids: If you can inject headers, you can often bypass internal authentication. Many internal APIs trust requests coming from localhost or specific subnets, relying on headers like X-User-ID or X-Role: Admin. If you can force wget to send those headers, you become the admin.
2. Cache Poisoning: This is the most dangerous vector. If wget is being used to fetch a resource that is then cached (e.g., a reverse proxy or CDN), injecting a split response could poison the cache for everyone. You could force the server to respond with a malicious JavaScript file instead of the expected jQuery library, and that malicious file gets cached and served to every subsequent user.
3. Request Smuggling: By manipulating the Content-Length or Transfer-Encoding headers via injection, you can desynchronize the connection between wget and the server (or a proxy in between). This is advanced territory, but it allows for stealing responses meant for other requests sharing the same TCP connection.
The remediation is straightforward but requires a binary update. You cannot configure your way out of this within wget itself.
1. Upgrade BusyBox: The patch was applied in late August 2025. You need a version of BusyBox newer than 1.37.0 (likely 1.37.1 or 1.38.0). If you are on a distro like Alpine or Debian, check specifically for CVE-2025-60876 in the changelogs.
2. Sanitize Inputs Upstream: Do not rely on the tool to be safe. If your application calls wget with user input, validate the URL in your application code first. Use a strict regex. Reject any input containing \r, \n, or raw spaces. If you are passing a URL to a shell command, ensure it is properly quoted, although quoting won't save you if the tool itself (wget) is vulnerable to the content of the string.
3. Switch Tools (If Possible): If you can, use curl (which has had strict protocol validation for years) or native HTTP libraries in your programming language. Using a CLI tool via system() or subprocess calls is historically a recipe for disaster.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
BusyBox wget BusyBox | <= 1.37.0 | Post-1.37.0 commits |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-113 (CRLF Injection) |
| Attack Vector | Network (Input Dependent) |
| CVSS v3.1 | 6.5 (Medium) |
| Impact | Header Injection, Request Splitting |
| EPSS Score | 0.05% |
| Exploit Status | PoC Available |
The software includes user-supplied data in an HTTP response header without validating that the data does not contain CR and LF characters.
A critical stored Cross-Site Scripting (XSS) vulnerability was identified in Froxlor server administration software panel before version 2.3.8. Authenticated customers with DNS editor privileges can inject malicious JavaScript into DNS TXT records. Because the application processes these values via a raw formatting callback without context-aware HTML entity encoding, the payload executes in the security context of administrative users who view the affected domain's DNS zones.
An authenticated administrator with privileges to manage admin accounts (such as change_serversettings) can execute arbitrary SQL commands via a second-order SQL injection vulnerability. The flaw resides in Froxlor's administrative API endpoints, specifically during the handling of IP address mapping parameters which are stored as serialized arrays and later interpolated without sanitization into active database queries. This vulnerability allows high-privileged administrative attackers to compromise the database. By injecting a payload into administrative profile metadata, an attacker can extract sensitive credentials, manipulate backend settings, or potentially disrupt database integrity. The vulnerability affects all versions of Froxlor prior to 2.3.8.
CVE-2026-54543 is a DNS Resource Record (RR) Injection vulnerability in Froxlor, an open-source server administration control panel. Prior to version 2.3.8, the DomainZones.add API command failed to perform strict sanitization and validation on the user-controlled record (label) and type parameters before serializing them into BIND-compatible zone files. An authenticated customer with DNS zone management permissions can inject control characters, breaking out of the original record context to define unauthorized resource records within managed zones.
CVE-2026-42533 is a critical security vulnerability discovered in NGINX Open Source, NGINX Plus, NGINX Ingress Controller, and related products, referred to as the 'Two-Pass Capture-Clobbering' bug. The flaw is situated within NGINX's internal evaluation engine when handling complex variables, exposing a heap-based buffer overflow and information leak when a configuration chains regular expression-based map directives with numbered capture groups. An unauthenticated remote attacker can exploit this weakness by transmitting crafted HTTP requests to trigger remote code execution or defeat ASLR.
Froxlor prior to version 2.3.8 contains a high-severity architectural flaw where the standalone lib/ajax.php entry point bypasses the centralized request validation in lib/init.php. Unauthenticated remote attackers can leverage Cross-Site Request Forgery (CSRF) to induce authenticated administrators to submit forged requests that modify API key whitelists and expiration dates, potentially yielding persistent, out-of-band administrative control.
An insecure data retrieval flaw in the Froxlor server administration panel API allows authenticated remote attackers to retrieve unredacted bcrypt password hashes and Base32-encoded Time-Based One-Time Password (TOTP) seeds. Affected endpoints include several 'get' and 'listing' handlers for customers, administrators, and FTP accounts. Utilizing these leaked parameters, attackers can crack the password hashes offline and concurrently generate valid second-factor authentication codes to completely bypass access controls.