CVE-2026-84838: Rpm: command injection in rpmuncompress via unescaped filenames passed to popen()
A flaw was found in rpmuncompress. This command injection vulnerability allows a local attacker to execute arbitrary commands. This occurs when rpmuncompress processes a specially crafted archive filename containing shell metacharacters, which are not properly escaped before being passed to shell command strings. Successful exploitation requires user interaction, where a user or automated workflow invokes rpmuncompress on the malicious file, leading to high impact on the confidentiality, integrity, and availability of data accessible to the invoking user.
Other sources
AIONLYREPORT package: rpm-4.19.1.1-23.el10 ------ Summary: Command Injection in rpmuncompress via Unescaped Filenames: attacker-controlled archive filenames are embedded into shell command strings and executed via popen(), allowing arbitrary command execution in the invoking user's context. Requirements to exploit: An attacker must supply a compressed file or source archive whose filename contains shell metacharacters and cause a user or automated workflow to invoke rpmuncompress on it. No prior privileges are required, but any resulting commands run with the privileges of the invoking process. Component affected: rpm-4.19.1.1-23.el10, tools/rpmuncompress.c (doUncompress(), doUntar(), and the popen() execution path in main()) Version affected: rpm-4.19.1.1-23.el10 Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H - 7.7 (HIGH) AV:L - The attacker must influence a local filename that is later processed by rpmuncompress; this is not a network-reachable trigger by itself. AC:L - The payload is carried directly in the filename, and the vulnerable code passes it into shell command strings without robust escaping. PR:N - No prior privileges on the target account are required to deliver or prepare a maliciously named archive. UI:R - A user or automated build or extraction workflow must invoke rpmuncompress on the attacker-controlled filename. S:U - The impact stays within the security scope of the invoking process. C:H - Successful command injection can read data available to the invoking user. I:H - Successful command injection can modify files or build outputs available to the invoking user. A:H - Successful command injection can disrupt or destroy data available to the invoking user. Impact: Moderate. The flaw can execute arbitrary shell commands in the context of the user running rpmuncompress, so confidentiality, integrity, and availability can all be affected for that user. However, exploitation is local and user-assisted: an attacker must get a maliciously named archive processed by the helper or by a workflow that invokes it. Under Red Hat's severity guidance, that is better classified as Moderate than Important because the available evidence does not show remote compromise or privilege escalation by itself. Embargo: no Reason: The issue is local and user-assisted, and there is straightforward short-term mitigation by avoiding untrusted archive filenames until a fixed package is available. Acknowledgement: Aisle Research Vulnerability Details: rpmuncompress constructs shell command strings from archive filenames and then executes those strings through the shell. In doUncompress(), the filename is appended directly to the command. In doUntar(), the filename is placed inside single quotes, but embedded single quotes in a filename break out of that quoting and let shell metacharacters be interpreted. The resulting command is later executed with popen(cmd, "r"). Available package code also indicates that this helper is used from build-time source and patch unpacking paths via %{rpmuncompress}, so exposure is not limited to purely manual invocation. Focused code snippet showing the vulnerable command construction sites: diff cmd = rstrscat(&cmd, " ", fn, NULL); ...
rasprintf(&buf, "%s '%s' | %s %s -", zipper, fn, tar, taropts);
rasprintf(&buf, "%s '%s' && %s spec '%s' --ruby > '%s'",
zipper, fn, gem, fn, gemspec);
rasprintf(&buf, "%s '%s'", zipper, fn); ...
rasprintf(&buf, "%s %s '%s'", tar, taropts, fn);
Steps to reproduce: 1. Build or install the rpmuncompress helper from the affected package. 2. Create a valid compressed file whose name contains shell metacharacters: bash printf 'hello\n' | gzip -c > "poc;id>/tmp/rpmuncompresspoc;#.gz" 3. Run the helper on the malicious filename: bash rpmuncompress "poc;id>/tmp/rpmuncompresspoc;#.gz" >/dev/null 2>&1 4. Verify command execution: bash test -s /tmp/rpmuncompresspoc && echo VULNERABLE Expected result: /tmp/rpmuncompresspoc is created and contains the output of id. A related trigger exists in extraction mode (-x) because doUntar() uses '%s' for fn without escaping embedded single quotes. Mitigation: Until a fixed package is available, do not pass untrusted archive filenames to rpmuncompress or workflows that invoke %{rpmuncompress}. Rename source and patch archives to remove shell metacharacters before build or extraction steps process them. Proposed Fix: Escape all attacker-controlled path fragments before embedding them into shell command strings, including the derived .gemspec path in the gem handling branch. The following minimal patch applies %{shescape:...} consistently at each vulnerable construction site: diff diff --git a/tools/rpmuncompress.c b/tools/rpmuncompress.c — a/tools/rpmuncompress.c +++ b/tools/rpmuncompress.c @@ -70,10 +70,13 @@ static char doUncompress(const char fn) { char cmd = NULL; + char qfn = NULL; const struct archiveTypes at = getArchiver(fn); if (at) { + qfn = rpmExpand("%{shescape:", fn, "}", NULL); cmd = rpmExpand(at->cmd, " ", at->unpack, NULL); cmd = rstrscat(&cmd, " ", fn, NULL); + cmd = rstrscat(&cmd, " ", qfn, NULL); + free(qfn); } return cmd; } @@ -82,6 +85,7 @@ static char doUntar(const char fn) { const struct archiveTypes at = NULL; char buf = NULL; + char qfn = NULL; char tar = NULL; const char taropts = verbose ? "-xvvof" : "-xof"; @@ -89,6 +93,7 @@ static char doUntar(const char fn) if ((at = getArchiver(fn)) == NULL) goto exit; + qfn = rpmExpand("%{shescape:", fn, "}", NULL); @@ -98,7 +103,7 @@ static char doUntar(const char fn) if (needtar) {
rasprintf(&buf, "%s '%s' | %s %s -", zipper, fn, tar, taropts); + rasprintf(&buf, "%s %s | %s %s -", zipper, qfn, tar, taropts); } else if (at->compressed == COMPRESSEDGEM) { @@ -111,11 +116,14 @@ static char doUntar(const char fn)
rasprintf(&buf, "%s '%s' && %s spec '%s' --ruby > '%s'",
zipper, fn, gem, fn, gemspec); + char qgemspec = rpmExpand("%{shescape:", gemspec, "}", NULL); + rasprintf(&buf, "%s %s && %s spec %s --ruby > %s", + zipper, qfn, gem, qfn, qgemspec); + free(qgemspec); @@ -118,10 +126,11 @@ static char doUntar(const char fn)
rasprintf(&buf, "%s '%s'", zipper, fn); + rasprintf(&buf, "%s %s", zipper, qfn); } @@ -122,10 +131,11 @@ static char doUntar(const char fn)
rasprintf(&buf, "%s %s '%s'", tar, taropts, fn); + rasprintf(&buf, "%s %s %s", tar, taropts, qfn); }
exit: + free(qfn); free(tar); return buf; } ------ This report was generated using AI technology. Always review AI-generated content prior to use
— Red Hat
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Until a fixed package is available, ensure all attacker-controlled fragments embedded into shell command strings are escaped using rpmExpand("%{shescape:", <fragment>, "}", NULL). This should be applied at each vulnerable construction site in doUncompress()/doUntar() where the filename (fn) and any derived .gemspec value are concatenated into the command string passed to popen(). For fn, use rpmExpand("%{shescape:", fn, "}", NULL) (and free the result); for the gemspec derived from gemspec path fragments, use rpmExpand("%{shescape:", gemspec, "}", NULL). Ensure the generated command is constructed from these escaped values rather than raw attacker-controlled strings.
rpmuncompress helper (tools/rpmuncompress.c) shell escaping for attacker-controlled archive filename/path fragments (fn, at->unpack-derived fragments, derived .gemspec) = Use rpmExpand("%{shescape:", fragment, "}", NULL) at every vulnerable command construction site (not just surrounding quoting)