Piotr Karwasz created COMPRESS-725:
--------------------------------------

             Summary: Unsafe Javadoc example in ArchiveStreamFactory
                 Key: COMPRESS-725
                 URL: https://issues.apache.org/jira/browse/COMPRESS-725
             Project: Commons Compress
          Issue Type: Improvement
            Reporter: Piotr Karwasz


h2. Summary

This Javadoc problem was reported to the Apache Security Team: the ZIP 
decompression example in {{ArchiveStreamFactory}} demonstrates an insecure 
extraction pattern that is vulnerable to Zip Slip path traversal. The library 
already ships a safe helper ({{ArchiveEntry.resolveIn()}}, since 1.26.0), but 
the documentation example does not use it, so anyone copying it inherits the 
flaw.

The report is quoted below verbatim, with the reporter's name and e-mail 
address redacted.

h2. Reported issue (quoted)

{quote}
*Affected:* Apache Commons Compress (all versions)
*Fixed in:* Documentation update recommended (library provides safe method 
since 1.26.0)

h3. Summary

The Javadoc example code in {{ArchiveStreamFactory.java}} (lines 73-79) 
demonstrates an insecure ZIP decompression pattern using 
{{dir.toPath().resolve(entry.getName())}} directly, without Zip Slip path 
traversal protection. While the library itself provides 
{{ArchiveEntry.resolveIn()}} (available since 1.26.0) for safe extraction, the 
official documentation example does not use it.

h3. Vulnerable code (from ArchiveStreamFactory.java:76)

{code:java}
/**
 * Decompressing a ZIP-File:
 *
 * <pre>
 * final InputStream is = Files.newInputStream(input.toPath());
 * ArchiveInputStream in = new 
ArchiveStreamFactory().createArchiveInputStream(ArchiveStreamFactory.ZIP, is);
 * ZipArchiveEntry entry = (ZipArchiveEntry) in.getNextEntry();
 * OutputStream out = 
Files.newOutputStream(dir.toPath().resolve(entry.getName())); // <- ZIP SLIP
 * IOUtils.copy(in, out);
 * out.close();
 * in.close();
 * </pre>
 */
{code}

The pattern {{dir.toPath().resolve(entry.getName())}} is vulnerable to Zip Slip 
attacks. An attacker can craft an archive with entry names containing {{../}} 
sequences (e.g., {{../../../tmp/poc}}) to write files outside the intended 
target directory.

h3. Safe alternative (available since 1.26.0)

{code:java}
default Path resolveIn(final Path parentPath) throws IOException {
    final String name = getName();
    final Path outputFile = parentPath.resolve(name).normalize();
    if (!outputFile.startsWith(parentPath)) {
        throw new ArchiveException("Zip slip '%s' + '%s' -> '%s'", parentPath, 
name, outputFile);
    }
    return outputFile;
}
{code}

The Javadoc example should use:

{code:java}
OutputStream out = Files.newOutputStream(entry.resolveIn(dir.toPath()));
{code}

h3. Attack chain

{code}
1. Attacker creates malicious ZIP with entry name "../../../tmp/poc"
2. Victim copies the Javadoc example and uses it to extract untrusted ZIP
3. new File(targetDir, entry.getName()) -> "/victim/../../../tmp/poc"
4. f.getCanonicalPath() -> "/tmp/poc"  (escapes target directory)
5. Files.newOutputStream(f.toPath()) -> writes to /tmp/poc
{code}

h3. CVSS scoring

* *CVSS v3.1:* 7.5 (High) - {{CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N}}
* *CVSS v4.0:* 7.5 (High) - 
{{CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N}}

h3. Impact

Any developer copying the official Javadoc example code introduces a Zip Slip 
path traversal vulnerability. Impact includes arbitrary file overwrite 
(potentially RCE via symlinks, cron jobs, or SSH authorized_keys).

h3. CVE request

*We request CVE assignment for this vulnerability.*

h3. References

* CWE-22 (Path Traversal): [https://cwe.mitre.org/data/definitions/22.html]
* Zip Slip pattern: [https://snyk.io/blog/zip-slip-vulnerability/]
* resolveIn() method (v1.26.0): 
[https://commons.apache.org/proper/commons-compress/changes-report.html#a1.26.0]
{quote}

h2. Suggested action

Update the {{ArchiveStreamFactory}} Javadoc example to extract entries via 
{{ArchiveEntry.resolveIn(dir.toPath())}} so the documented pattern is safe by 
default.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to