Skip to content

fix(security): align audit symlink_escape boundary with skill loader#60513

Closed
menhguin wants to merge 1 commit into
openclaw:mainfrom
menhguin:fix/audit-skill-symlink-boundary-v2
Closed

fix(security): align audit symlink_escape boundary with skill loader#60513
menhguin wants to merge 1 commit into
openclaw:mainfrom
menhguin:fix/audit-skill-symlink-boundary-v2

Conversation

@menhguin

@menhguin menhguin commented Apr 3, 2026

Copy link
Copy Markdown

The skills.workspace.symlink_escape audit probe checked whether skill
file realpaths escaped the workspace root (~/.openclaw/workspace/),
but the skill loader (resolveContainedSkillPath) checks against the
skills directory root (~/.openclaw/workspace/skills/).

This mismatch meant symlinks like:

workspace/skills/my-skill -> workspace/other-dir/skills/my-skill

...would resolve inside the workspace root (audit says OK) but outside
the skills directory (loader silently rejects). The skill would fail
to load with zero feedback from openclaw security audit.

Fix: check against the skills directory realpath in the audit probe,
matching the loader's boundary. Add test for the in-workspace but
outside-skills-dir case.

Relates to #49408


Replaces #60144 which had a stale orphan branch causing 11k+ file diff.

The skills.workspace.symlink_escape audit probe checked whether skill
file realpaths escaped the workspace root (~/.openclaw/workspace/),
but the skill loader (resolveContainedSkillPath) checks against the
skills directory root (~/.openclaw/workspace/skills/).

This mismatch meant symlinks like:
  workspace/skills/my-skill -> workspace/other-dir/skills/my-skill

...would resolve inside the workspace root (audit says OK) but outside
the skills directory (loader silently rejects). The skill would fail
to load with zero feedback from `openclaw security audit`.

Fix: check against the skills directory realpath in the audit probe,
matching the loader's boundary. Add test for the in-workspace but
outside-skills-dir case.

Relates to openclaw#49408
@menhguin
menhguin requested a review from a team as a code owner April 3, 2026 20:18
@greptile-apps

greptile-apps Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a boundary mismatch in collectWorkspaceSkillSymlinkEscapeFindings: the audit probe now checks realpaths against the skills/ subdirectory realpath instead of the workspace root, matching the boundary enforced by the skill loader (resolveContainedSkillPath in workspace.ts). A new test covers the previously-silent "inside workspace but outside skills dir" case. The only gap is that the remediation string on line 933 still says "workspace root" while the title and detail have been updated to say "skills directory".

Confidence Score: 5/5

Safe to merge; the logic fix is correct and well-tested, with only a minor remediation string inconsistency.

All remaining findings are P2. The core boundary alignment fix is correct and directly matches the loader's behavior. The new test case validates the previously uncaught scenario.

src/security/audit-extra.async.ts line 933 — remediation text should say "skills directory" not "workspace root".

Comments Outside Diff (1)

  1. src/security/audit-extra.async.ts, line 932-933 (link)

    P2 Remediation text still references workspace root

    The title and detail were correctly updated to say "skills directory", but the remediation string still says "inside the workspace root". A symlink that resolves inside the workspace but outside skills/ is exactly the new case being caught, so a user following this remediation ("keep inside workspace root") would think they've fixed the issue when they haven't.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/security/audit-extra.async.ts
    Line: 932-933
    
    Comment:
    **Remediation text still references workspace root**
    
    The `title` and `detail` were correctly updated to say "skills directory", but the `remediation` string still says "inside the workspace root". A symlink that resolves inside the workspace but outside `skills/` is exactly the new case being caught, so a user following this remediation ("keep inside workspace root") would think they've fixed the issue when they haven't.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/security/audit-extra.async.ts
Line: 932-933

Comment:
**Remediation text still references workspace root**

The `title` and `detail` were correctly updated to say "skills directory", but the `remediation` string still says "inside the workspace root". A symlink that resolves inside the workspace but outside `skills/` is exactly the new case being caught, so a user following this remediation ("keep inside workspace root") would think they've fixed the issue when they haven't.

```suggestion
    remediation:
      "Keep workspace skills inside the skills directory (replace symlinked escapes with real in-workspace files), or move trusted shared skills to managed/bundled skill locations.",
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(security): align audit symlink_escap..." | Re-trigger Greptile

@clawsweeper

clawsweeper Bot commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Closing this as duplicate or superseded after Codex automated review.

PR #60513 is a duplicate of the same remaining audit/loader boundary fix already tracked by open PR #60155. Current main still has the mismatch, so this is not implemented, but cleanup should keep one canonical PR rather than two parallel copies of the same fix.

Best possible solution:

Close #60513 as duplicate/superseded and continue the fix in #60155. The eventual landed change should make the audit check compare against the resolved workspace skills directory, update finding/docs wording from workspace root to skills directory, and add the inside-workspace/outside-skills regression test.

What I checked:

So I’m closing this here and keeping the remaining discussion on the canonical linked item.

Codex Review notes: model gpt-5.5, reasoning high; reviewed against e29d3516bf05.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant