Skip to content

fix(opencode): reject path traversal in remote skill discovery#5

Merged
CreatorGhost merged 2 commits into
devfrom
skill-path-traversal
Jul 11, 2026
Merged

fix(opencode): reject path traversal in remote skill discovery#5
CreatorGhost merged 2 commits into
devfrom
skill-path-traversal

Conversation

@CreatorGhost

@CreatorGhost CreatorGhost commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Port of upstream anomalyco/opencode#36364.

Validates skill.name and every files[] entry from remote skill indexes before any filesystem write: rejects traversal segments, absolute paths, URL-encoded escapes, cross-origin resources, and destinations outside the per-skill cache root.

Verified: bun test test/skill/discovery.test.ts (11 pass, includes new traversal regression tests) and bun typecheck from packages/opencode. Applied cleanly (no fork adaptations needed).

Summary by CodeRabbit

  • Bug Fixes

    • Strengthened validation when downloading remote skills to prevent path traversal, unsafe filenames, and cross-origin downloads.
    • Ignored malformed or incomplete skill metadata, including entries missing required skill files.
    • Added safeguards to ensure downloaded content remains within the expected local cache.
  • Tests

    • Added coverage for malicious skill names, file paths, absolute paths, and external download URLs.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@CreatorGhost, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 38 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8f30031e-d269-4393-8bb2-bf07c9e94a81

📥 Commits

Reviewing files that changed from the base of the PR and between 24b508d and fdb99e5.

📒 Files selected for processing (2)
  • packages/opencode/src/skill/discovery.ts
  • packages/opencode/test/skill/discovery.test.ts
📝 Walkthrough

Walkthrough

Skill discovery now validates remote skill names, file paths, filesystem roots, and URL origins before downloading or caching files. Tests add hostile metadata cases covering traversal, absolute paths, and cross-origin URLs.

Changes

Secure skill discovery

Layer / File(s) Summary
Metadata and URL validation
packages/opencode/src/skill/discovery.ts
Adds safe-segment and safe-relative-path checks, derives index.json from the source URL, filters unsafe skills and files, constrains cache roots, and requires same-origin file URLs.
Safe refresh and hostile-input coverage
packages/opencode/src/skill/discovery.ts, packages/opencode/test/skill/discovery.test.ts
Refreshes skills using precomputed safe download mappings and tests traversal, absolute-path, and cross-origin metadata without allowing hostile downloads.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Discovery
  participant RemoteIndex
  participant Validator
  participant SkillServer
  participant Cache
  Discovery->>RemoteIndex: Fetch index.json
  RemoteIndex-->>Discovery: Return skill metadata
  Discovery->>Validator: Validate names, paths, roots, and origins
  Validator-->>Discovery: Return safe download mappings
  Discovery->>SkillServer: Download mapped files
  SkillServer-->>Discovery: Return file contents
  Discovery->>Cache: Stage and refresh validated skill files
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main change: blocking path traversal in remote skill discovery.
Description check ✅ Passed The description covers the fix and verification, but it omits template sections like the issue link and checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch skill-path-traversal

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@CreatorGhost

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CreatorGhost

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 23 minutes.

@CreatorGhost

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 4 minutes.

@CreatorGhost

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 59 minutes.

@CreatorGhost

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 22 minutes.

@CreatorGhost

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 7 minutes.

@CreatorGhost

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/opencode/test/skill/discovery.test.ts (1)

196-246: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Good regression coverage; consider adding a case for the bare drive-letter name gap.

The four traversal/absolute/cross-origin cases are well-targeted and match the implementation's rejection paths. Given the isSafeSegment gap flagged in discovery.ts (bare "C:"-style skill names), once that's hardened, a corresponding hostileSkills = [{ name: "C:", files: ["SKILL.md"] }] case would be a useful addition to lock in the fix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/test/skill/discovery.test.ts` around lines 196 - 246, Add a
live regression test alongside the existing traversal cases in discovery.test.ts
for a bare drive-letter skill name: set hostileSkills to [{ name: "C:", files:
["SKILL.md"] }], reset hostileDownloads, call Discovery.Service.pull, and assert
it returns no directories without downloading files.
packages/opencode/src/skill/discovery.ts (1)

143-162: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No diagnostic logging when a skill is dropped due to unsafe files[] entries.

Skills missing SKILL.md get a warning (Lines 155-162), but skills rejected because files.some(item => item === undefined) (Line 143-145) — i.e. containing a traversal/absolute/cross-origin file entry — are silently dropped with no log. This makes it hard for legitimate skill authors to debug why their skill vanished, unlike the missing-SKILL.md case which does warn.

♻️ Suggested addition
         if (files.some((item) => item === undefined)) {
+          yield* Effect.logWarning("skill entry has unsafe file path", { url: index, skill: skill.name })
           return []
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/skill/discovery.ts` around lines 143 - 162, Add
diagnostic warning logging in the skill mapping flow when files.some((item) =>
item === undefined) rejects a skill, including the skill identity and relevant
index or file context. Preserve the existing empty-result behavior, and keep the
warning consistent with the missing-SKILL.md logging in the surrounding
discovery logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/opencode/src/skill/discovery.ts`:
- Around line 143-162: Add diagnostic warning logging in the skill mapping flow
when files.some((item) => item === undefined) rejects a skill, including the
skill identity and relevant index or file context. Preserve the existing
empty-result behavior, and keep the warning consistent with the missing-SKILL.md
logging in the surrounding discovery logic.

In `@packages/opencode/test/skill/discovery.test.ts`:
- Around line 196-246: Add a live regression test alongside the existing
traversal cases in discovery.test.ts for a bare drive-letter skill name: set
hostileSkills to [{ name: "C:", files: ["SKILL.md"] }], reset hostileDownloads,
call Discovery.Service.pull, and assert it returns no directories without
downloading files.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 87143fc4-e123-4cb2-b44b-e967b68aaec1

📥 Commits

Reviewing files that changed from the base of the PR and between 67e2bd4 and 24b508d.

📒 Files selected for processing (2)
  • packages/opencode/src/skill/discovery.ts
  • packages/opencode/test/skill/discovery.test.ts

…e entries

Addresses CodeRabbit review findings on the anomalyco#36364 port.
@CreatorGhost

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CreatorGhost CreatorGhost merged commit ddda82d into dev Jul 11, 2026
4 of 7 checks passed
@CreatorGhost CreatorGhost deleted the skill-path-traversal branch July 11, 2026 21:33
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.

1 participant