CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2025-60876
6.50.05%

Breaking the Box: Deep Dive into BusyBox wget CRLF Injection

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 15, 2026·7 min read·18 visits

PoC Available

Executive Summary (TL;DR)

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.

The Hook: The Swiss Army Knife with a Loose Blade

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.

The Flaw: When Text Becomes Syntax

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.

The Code: Autopsy of a Socket Writer

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.

The Exploit: Popping the Box

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.

The Impact: Why Should We Panic?

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 Fix: How to Stop the Bleeding

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.

Official Patches

BusyBox GitOfficial patch implementation
DebianDebian security tracker entry

Fix Analysis (1)

Technical Appendix

CVSS Score
6.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N
EPSS Probability
0.05%
Top 84% most exploited

Affected Systems

BusyBox wget applet (versions <= 1.37.0)Alpine Linux containers (older images)Embedded Linux firmware (OpenWrt, Buildroot based systems using affected BusyBox)CI/CD pipelines using BusyBox for artifact retrieval

Affected Versions Detail

Product
Affected Versions
Fixed Version
BusyBox wget
BusyBox
<= 1.37.0Post-1.37.0 commits
AttributeDetail
CWE IDCWE-113 (CRLF Injection)
Attack VectorNetwork (Input Dependent)
CVSS v3.16.5 (Medium)
ImpactHeader Injection, Request Splitting
EPSS Score0.05%
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1210Exploitation of Remote Services
Lateral Movement
CWE-113
Improper Neutralization of CRLF Sequences in HTTP Headers

The software includes user-supplied data in an HTTP response header without validating that the data does not contain CR and LF characters.

Known Exploits & Detection

Mailing ListInitial report and PoC by Takeuchi Yuma demonstrating X-Secret header injection.

Vulnerability Timeline

Vulnerability reported to BusyBox mailing list
2025-08-23
Patch submitted by Takeuchi Yuma
2025-08-28
CVE-2025-60876 Assigned/Published
2025-11-10

References & Sources

  • [1]BusyBox Mailing List Disclosure

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.