Skip to content

fix(cli): prevent directory traversal in skill file installation#2235

Merged
fahreddinozcan merged 3 commits intoupstash:masterfrom
spidershield-contrib:fix/path-traversal-installer
Mar 19, 2026
Merged

fix(cli): prevent directory traversal in skill file installation#2235
fahreddinozcan merged 3 commits intoupstash:masterfrom
spidershield-contrib:fix/path-traversal-installer

Conversation

@spidershield-contrib
Copy link
Copy Markdown
Contributor

@spidershield-contrib spidershield-contrib commented Mar 15, 2026

Summary

Fixes #2234

  • installer.ts: Replace path.join() with path.resolve() and add a boundary check that ensures the resolved file path stays within the skill directory. Throws an error if a path would escape the boundary.
  • github.ts: Add defense-in-depth check that rejects file paths containing .. at download time, before they reach the installer.

Vulnerability Details

installSkillFiles() used path.join(skillDir, file.path) where file.path comes from the GitHub API tree response. A malicious skill repository could include files with ../ path sequences, causing path.join() to resolve to locations outside the intended skill directory. This allowed arbitrary file writes as the current user.

Changes

File Change
packages/cli/src/utils/installer.ts Use resolve() + boundary check before writeFile()
packages/cli/src/utils/github.ts Reject paths containing .. at download time

Test Plan

  • npx tsc --noEmit -p packages/cli/tsconfig.json passes with zero errors
  • Manual: verify path.resolve("/base/skill", "../../../etc/passwd")/etc/passwd which is caught by the startsWith guard
  • Manual: verify legitimate skill paths like src/index.ts still install correctly

Found by SpiderShield security scanner

spidershield-contrib and others added 2 commits March 14, 2026 21:52
installSkillFiles() used path.join() with unsanitized file paths from
GitHub API responses. A malicious skill repository could include files
with "../" sequences in their paths, allowing writes outside the
intended skill directory.

Changes:
- installer.ts: use path.resolve() and verify the resolved path stays
  within the skill directory boundary before writing
- github.ts: reject file paths containing ".." at download time as an
  additional defense-in-depth check
@fahreddinozcan fahreddinozcan merged commit 8c5cf7d into upstash:master Mar 19, 2026
1 of 2 checks passed
@spidershield-contrib
Copy link
Copy Markdown
Contributor Author

Hi @fahreddinozcan,

Now that the fix has been merged and released for a few weeks, I'd
like to formalize this vulnerability with a GitHub Security Advisory
so that:

  1. A CVE ID gets assigned
  2. Users of older ctx7 versions receive Dependabot alerts to upgrade
  3. The vulnerability is indexed in the GitHub Advisory Database

I attempted to file a draft advisory at
https://github.com/upstash/context7/security/advisories/new but it
returns 404, which means Private Vulnerability Reporting is not
enabled for this repo.

Two options:

Option 1 (easier for you): You (as maintainer) file the advisory
directly. I can draft the full description, CVSS score, and credit
fields if helpful — just let me know.

Option 2: Enable Private Vulnerability Reporting in repo Settings
→ Code security → Private vulnerability reporting → Enable. This lets
external researchers (including me) file draft advisories that you
can then review and publish.

For this specific issue, Option 1 is simpler. I can share the full
draft content right here in the thread if you prefer.

Details I already have ready:

  • CVSS v3.1: 9.3 (Critical) — AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N
  • CWE-22: Improper Limitation of a Pathname to a Restricted Directory
  • Credit: Owen Wang / SpiderRating (via @spidershield-contrib)

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security: Directory traversal in CLI skill installer allows arbitrary file writes

2 participants