Share
## https://sploitus.com/exploit?id=832004FA-0747-5D4D-9657-212A52320D8C
# decompress โ€” Symlink & Hardlink Path Traversal (Arbitrary File Write)

**CWE-59:** Improper Link Resolution Before File Access
**Advisory ref:** GHSA-mp2f-45pm-3cg9 (fix only in the `@xhmikosr/decompress` fork)

Working proof-of-concept for an arbitrary file write in the `decompress` npm
package (4.2.1, latest) via archive symlink and hardlink entries that escape the
output directory.

> PoCs run entirely in `/tmp`, write to throwaway marker files, and clean up
> after themselves. Use them only to verify the flaw on systems you control.

---

## Summary

| Field | Value |
|-------|-------|
| **Package** | `decompress` |
| **Repository** | `kevva/decompress` |
| **Version** | 4.2.1 (latest) |
| **Downloads** | 17.6M weekly |
| **CWE** | CWE-59 โ€” Improper Link Resolution Before File Access |
| **CVSS** | 7.5 HIGH (AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H) if escalated to RCE |
| **Fix** | `@xhmikosr/decompress` 10.2.1 / 11.1.3 (fork only, original unpatched) |

---

## How It Works

`decompress()` extracts archives and confines writes to an output directory.
The confinement is incomplete in two ways.

### Vulnerability 1: Symlink Escape

In `index.js:112-124`:

```
line 104-109: realDestinationDir check -> runs for hard links (line 113)
line 116-118: symlink created immediately -> NO CHECK
```

A symlink entry pointing outside the output directory (e.g. `escape.txt -> ../../marker.txt`)
is created with no validation. Any later write through that symlink overwrites an
arbitrary file on the host.

### Vulnerability 2: Hardlink Write Bypass

`preventWritingThroughSymlink` uses `fsP.readlink()` to block symlink writes.
A hardlink entry is created with `fsP.link()` and is **not** covered by that
check. A hardlink pointing at a file outside the output directory, followed by a
write to the same path, overwrites the external file.

### Why both matter

- Attacker only needs the victim to extract a crafted archive.
- No authentication, no privileges, no special user interaction.
- No "does not require" list matters once a malicious zip is extracted.

---

## Proof of Concept

```bash
npm install decompress@4.2.1
node poc_symlink_bypass.js
node poc_hardlink_bypass.js
```

### Symlink run

```
[+] Symlink created: /tmp/decompress-poc-*/output/escape.txt -> ../marker.txt
[+] Symlink points OUTSIDE output directory!
[+] VULNERABILITY CONFIRMED: Arbitrary file write via symlink
    Before: ORIGINAL_CONTENT
    After:  POC_ARBITRARY_WRITE_...
```

### Hardlink run

```
[+] Target file content before: ORIGINAL_CONTENT
[+] Extraction Completed!
[+] Target file content after: POC_HARDLINK_OVERWRITE_SUCCESS
[+] SUCCESS: Bypass confirmed! File outside output directory was overwritten.
```

---

## Impact

- Arbitrary file overwrite via a crafted zip/tar archive.
- Overwritable targets include: SSH keys, cron jobs, shell profiles, config
  files, application binaries.
- Escalation to RCE is possible depending on context (see `docs/analysis.md`).

---

## Recommended Fix

Port `ensureLinkTargetInsideOutput()` from the `@xhmikosr/decompress` fork.
It validates that both symlink and hardlink targets resolve inside the output
directory before creating the link.

---

## Files

| File | Purpose |
|------|---------|
| `poc_symlink_bypass.js` | Symlink escape -> arbitrary write |
| `poc_hardlink_bypass.js` | Hardlink write bypass of `preventWritingThroughSymlink` |
| `docs/analysis.md` | Root-cause breakdown and RCE escalation vectors |
| `advisory.md` | Ready-to-send vendor advisory |

## Disclosure

Vendor disclosure initiated 2026-07-17 (see `advisory.md`). The original package
remains unpatched at 4.2.1; the fix exists only in the maintained fork.

## License

MIT โ€” provided for defensive security research and education only.