5692 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / cover-letter.txt TXT
Subject: [PATCH v3] wget: percent-encode control characters and space in the request URL

This follows up Radoslav Kolev's v2 [1] and the earlier report and patch from
Takeuchi Yuma [2], both for CVE-2025-60876: a crafted URL injects HTTP headers
through wget's request line.

The v1 and v2 patches reject any URL byte <= 0x20 and call bb_error_msg_and_die.
That closes the injection, but it also rejects a plain space, so a URL like
http://example.org/foo bar that used to work now errors. That behavior change
is the reason the fix has not been picked up downstream (Alpine is holding its
backport on it, see [3]).

This version encodes the path and rejects in the host, matching GNU wget and
curl:

  - Path: control bytes (0x00-0x1f), space (0x20), and DEL (0x7f) in the
    request-target are percent-encoded. CR and LF can no longer reach the
    request line. An existing '%' is left alone, so an already-encoded path is
    not double-encoded, and http://example.org/foo bar is sent as /foo%20bar
    (no regression).
  - Host: those same bytes are rejected. A hostname cannot legitimately contain
    them, and percent-encoding is not defined for the authority component. This
    closes the proxy case, where the host is placed in the absolute-form
    request-target and the Host: header but is not resolved locally. GNU wget
    (since CVE-2017-6508) and curl reject control characters in the host too.

The change is one helper in networking/wget.c. It does not touch any config or
applet wiring. Size impact on aarch64 defconfig (scripts/bloat-o-meter):

  add/remove: 0/0 grow/shrink: 2/0 up/down: 185/0    Total: 185 bytes
  (wget_main +142, .rodata +43)

I tested it with a local listener that echoes the raw request, direct and via
an http_proxy:

  - direct: vanilla sends "Evil: injected" as a header; patched sends
    "GET /x%0D%0AEvil:%20injected HTTP/1.1" and the header does not appear,
  - proxy: vanilla injects a header through a CRLF host; patched dies with
    "bad character in URL host" and sends nothing,
  - http://example.org/foo bar -> /foo%20bar, http://example.org/foo%20bar stays
    /foo%20bar (not %2520), a normal proxy request is unchanged,
  - the testsuite/wget tests all pass.

Credit to Radoslav Kolev and Takeuchi Yuma for the original analysis and
patches, and to Emmanuel Deloget and Walter Harms for the v2 review.

[1] https://lists.busybox.net/pipermail/busybox/2025-November/091840.html
[2] https://lists.busybox.net/pipermail/busybox/2025-August/091710.html
[3] https://gitlab.alpinelinux.org/alpine/aports/-/work_items/17872

Signed-off-by: Hayden Barnes <[email protected]>