GHSA-rfx7-4xw3-gh4m: @appium/support has a Zip Slip arbitrary file write in its ZIP extraction
Summary`@appium/support` contains a ZIP extraction implementation (`extractAllTo()` via `ZipExtractor.extract()`) with a path traversal (Zip Slip) check that is non-functional. The check at line 88 of `packages/support/lib/zip.js` creates an `Error` object but never throws it, allowing malicious ZIP entries with `../` path components to write files outside the intended destination directory. This affects all JS-based extractions (the default code path), not only those using the `fileNamesEncoding` option.Severity**Medium** (CVSS 3.1: 6.5)`CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N`**Attack Vector:** Network — malicious ZIP files can be supplied over the network (e.g., app packages via URL)**Attack Complexity:** Low — no special conditions required beyond providing a crafted ZIP**Privileges Required:** None — no authentication needed to supply a malicious archive**User Interaction:** Required — a user or automation system must initiate extraction of the attacker's archive**Scope:** Unchanged — impact stays within the file system permissions of the Appium process**Confidentiality Impact:** None — the vulnerability enables file writes, not reads**Integrity Impact:** High — arbitrary file write to any location writable by the process**Availability Impact:** None — no direct availability impactAffected Component`packages/support/lib/zip.js` — `ZipExtractor.extract()` (line 88) and `ZipExtractor.extractEntry()` (lines 111-145)CWE**CWE-22**: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')DescriptionMissing `throw` renders Zip Slip protection non-functionalThe `ZipExtractor.extract()` method contains a path traversal check intended to prevent Zip Slip attacks. However, the check creates an `Error` object as a bare expression without the `throw` keyword, making it a no-op:The presence of a well-formatted error message and surrounding try/catch block (lines 95-99) strongly suggests the `throw` keyword was accidentally omitted.yauzl does not provide its own traversal protectionThe upstream `yauzl` library explicitly [does not offer path traversal protection](https://github.com/thejoshwolfe/yauzl#no-path-traversal-protection) regardless of the `decodeStrings` setting. This means the vulnerability affects **all** JS-based extractions through `ZipExtractor`, not only those where `fileNamesEncoding` is set. The `fileNamesEncoding` option bypasses yauzl's string decoding (`decodeStrings: false`), but even with `decodeStrings: true`, yauzl passes through `../` path components without rejection.Unprotected write sinksThe `extractEntry` method writes to attacker-controlled paths with no additional validation:Additionally, `_extractEntryTo()` (line 263) used by `readEntries()` has no traversal check at all:Default code path is vulnerableThe `extractAllTo()` function uses the JS-based `ZipExtractor` by default. The system unzip fallback (`useSystemUnzip: true`) must be explicitly enabled and only provides protection if the system binary succeeds:Proof of ConceptImpact**Arbitrary file write**: An attacker can write files to any location writable by the Appium process, outside the intended extraction directory.**Arbitrary symlink creation**: Malicious ZIP entries with symlink attributes can create symlinks pointing to arbitrary targets, enabling further attacks on subsequent file operations.**Potential code execution**: By overwriting scripts, configuration files, `node_modules` contents, cron jobs, shell profiles, or other executable artifacts, arbitrary file write can chain into remote code execution.**Affects all JS-based extractions**: The default code path (without `useSystemUnzip: true`) is vulnerable regardless of whether `fileNamesEncoding` is set.Recommended RemediationOption 1: Add the missing `throw` keyword (preferred — minimal fix)This is the lowest-risk fix: it restores the clearly intended behavior of the existing check. The try/catch block at lines 95-99 will catch the error, set `canceled = true`, close the zip, and reject the promise — exactly the designed error-handling flow.Option 2: Add traversal protection to `_extractEntryTo` as wellThe `_extractEntryTo` function (line 262) also lacks a traversal check. For defense-in-depth, add validation there too:CreditThis vulnerability was discovered and reported by [bugbunny.ai](https://bugbunny.ai).
CVSS v3.1: 6.5