[CVE-2026-39245] Path traversal via indexOf containment bypass → arbitrary file write (CVE-2020-12265 bypass)
- Dominant language
- JavaScript
- Stars
- 419
- Forks
- 55
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
`decompress` (<= 4.2.1) uses `String.indexOf()` to verify the resolved path is inside the output directory, without enforcing a path-separator boundary. A sibling directory that shares a string prefix with the output directory passes the check, enabling directory traversal and **arbitrary file write** outside the extraction target. This bypasses the fix for CVE-2020-12265.
- **CVE:** CVE-2026-39245
- **CWE:** CWE-22 (Improper Limitation of a Pathname to a Restricted Directory)
- **Affected versions:** decompress <= 4.2.1
- **Fixed:** no fix released yet
- **Attack vector:** remote (crafted archive), no authentication required
## Affected component
`index.js` (lines ~29 and ~106):
realDestinationDir.indexOf(realOutputPath) !== 0
For `realOutputPath = "/tmp/app"`, a path of `"/tmp/app_config"` returns index `0` and incorrectly passes the check even though it is outside `/tmp/app`.
## Impact
Combined with the unvalidated symlink creation in the same package, an attacker can write arbitrary files into directories adjacent to the extraction target (e.g. output `/tmp/app`, escape to `/tmp/app_config`).
## Proof of concept
Given an output directory `/tmp/decompress_poc_app/`, an archive that (1) creates a symlink to the sibling `/tmp/decompress_poc_app_config` and (2) writes a file traversing through that symlink results in `pwned.txt` being written to `/tmp/decompress_poc_app_config/pwned.txt` — outside the intended output directory — because the `indexOf` check passes on the shared prefix.
## Correct fix
Append a path separator before the containment check:
realParentPath.indexOf(realOutputPath + path.sep) !== 0
## Mitigation
- Do not extract untrusted archives with this package until fixed.
Reported by Daniel Pua (devploit).
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in index.js around lines 29 and 106, where resolved paths are checked against the output directory. Reproduce the supplied sibling-directory path traversal proof of concept, then verify that shared-prefix paths are rejected while paths inside the output directory remain accepted. Done means the containment bypass no longer permits writes outside the extraction target.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- Half a day
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100