fix(skill): prevent zip-slip path traversal in extractZipToFS (CWE-22)#220
Open
sebastiondev wants to merge 2 commits intoAIPexStudio:mainfrom
Open
fix(skill): prevent zip-slip path traversal in extractZipToFS (CWE-22)#220sebastiondev wants to merge 2 commits intoAIPexStudio:mainfrom
sebastiondev wants to merge 2 commits intoAIPexStudio:mainfrom
Conversation
…WE-22) extractZipToFS() used relative paths from ZIP entries to construct write targets without validating that the resolved path stays within the intended skill directory. A crafted ZIP with entries like "../../other-skill/SKILL.md" could write files outside the target directory, overwriting other skills in the ZenFS virtual filesystem. Add normalizePath() to resolve ".." segments in browser contexts and validate every resolved path starts with the target directory prefix before writing. Entries that escape the target are skipped with a console warning.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes a zip-slip path traversal vulnerability (CWE-22) in
extractZipToFSinpackages/browser-runtime/src/skill/lib/utils/zip-utils.ts. A malicious skill ZIP can contain entries with../segments (or absolute paths) that, when extracted, write outside the intended skill target directory inside the ZenFS virtual filesystem.Vulnerability details
packages/browser-runtime/src/skill/lib/utils/zip-utils.tsextractZipToFSskill-storage.saveSkillderives atargetPathlike/skills/<name>(the name comes from the ZIP's ownSKILL.mdfrontmatter) and callsextractZipToFS(zipData, targetPath). Pre-fix, each entry's path was joined directly:`${targetPath}/${relativePath}`and written to ZenFS without verifying the resolved location stayed withintargetPath. An entry such as../other-skill/SKILL.mdtherefore writes into a sibling skill directory.Fix
Added a small
normalizePath()helper (POSIX-style, no Nodepathdependency to keep it browser-safe) that resolves.and..segments. Before writing any entry, the resolved full path is normalized and checked against the normalized target with astartsWith(target + "/")guard (the trailing slash prevents prefix-confusion attacks like/skills/foomatching/skills/foobar). Entries that escape the target are skipped with a warning and extraction continues for the remaining valid entries.The same
normalizedFullPathis then used for themkdirandwriteFilecalls so the on-disk layout matches what was validated.Tests
Added
zip-utils.test.tswith 24 unit tests covering:normalizePathbehavior on relative, absolute, dot, and double-dot segments, trailing slashes, and edge cases.../escape, deep../../../etc/passwd-style payloads, absolute entry paths (/etc/passwd), sibling-directory escape (../other-skill/SKILL.md), and prefix-confusion (/skills/foobarvs target/skills/foo).All tests pass locally. The diff is intentionally minimal — only
zip-utils.tsand the new test file are touched.Security analysis
Preconditions: the user must install a crafted skill ZIP through the extension's skill-upload flow.
Why it matters even with that precondition: once a skill is installed, the runtime sandboxes it to its own directory and skills are expected to only touch their own files. Zip-slip breaks that boundary — a malicious skill can overwrite other installed skills'
SKILL.mdor scripts. That enables persistence and impersonation: even after the malicious skill itself is removed, modified files in unrelated skills remain. This is a real scope/privilege escalation within the skill system, distinct from "the skill you just installed runs code."Scope of impact: limited to the ZenFS virtual filesystem inside the extension — no host-filesystem reach. Skills already execute scripts via
chrome.scripting, so the marginal capability granted by zip-slip is "tamper with other skills," not new RCE. We'd characterize severity as moderate rather than critical, but worth fixing because the mitigation is small and self-contained.Adversarial review: before submitting, we tried to disprove the finding. We checked whether
saveSkillor upstream code already validates entry paths (it doesn't — the target is derived from the ZIP's own metadata and entries are trusted), whether ZenFS itself rejects..segments (it normalizes and writes wherever the resolved path lands), and whether the fact that skills already run code makes this redundant. It isn't redundant: the attack surface is cross-skill tampering and persistence, which the runtime's per-skill sandboxing is otherwise meant to prevent.Notes for review
normalizePathhelper is intentionally inline rather than pulling inpath-browserify, to keep the change minimal and dependency-free.continue(skip + warn) behavior preserves backward compatibility for benign ZIPs while neutralizing malicious entries; happy to switch to a hard error if you'd prefer.cc @lewiswigmore