Skip to content

feat(code): in-the-moment trust prompt for symlinked skills#4200

Merged
Mason Daugherty (mdrxy) merged 15 commits into
mainfrom
mdrxy/code/skill-symlink-trust
Jul 6, 2026
Merged

feat(code): in-the-moment trust prompt for symlinked skills#4200
Mason Daugherty (mdrxy) merged 15 commits into
mainfrom
mdrxy/code/skill-symlink-trust

Conversation

@mdrxy

@mdrxy Mason Daugherty (mdrxy) commented Jun 24, 2026

Copy link
Copy Markdown
Member

Skills whose SKILL.md resolves outside trusted directories (e.g. via a symlink) can now be approved in the moment via a trust prompt, instead of requiring a quit-and-relaunch to edit config. Approved directories are persisted to ~/.deepagents/.state/skill_trust.json and can be audited or revoked with dcode skills trust list|revoke|clear.


Today, invoking a skill whose SKILL.md resolves (via symlink) outside every trusted skill root fails hard with a PermissionError, and the only way to proceed is to quit, set DEEPAGENTS_CODE_EXTRA_SKILLS_DIRS / [skills].extra_allowed_dirs, and relaunch. This adds an in-the-moment approval flow modeled on the existing project-level MCP trust screen.

When containment fails, the TUI shows a SkillTrustScreen naming the skill and the resolved target directory. Allowing reads the skill immediately, persists the resolved target directory to a new trust store at ~/.deepagents/.state/skill_trust.json (managed by skills/trust.py, mirroring mcp_trust.py), and extends the in-session containment allowlist. Denying is safe and is remembered for the rest of the session so the user is not re-nagged. The non-interactive (-x) path keeps the existing hard-fail + hint.

Trust is keyed by the resolved target directory — the canonical path shown to the user at approval time, stored as-is and never re-resolved. Two distinct post-approval symlink swaps are caught by two distinct layers, so neither grants access the user never approved:

  • Re-pointing the discovery symlink (the SKILL.md path) at a new target is caught by containment enforcement in load_skill_content: the new target is not on the allowlist, so the read is refused and the user is re-prompted. The stored trust entry — the original resolved target — is untouched.
  • Replacing the stored directory itself (or one of its parents) with a symlink is caught by the resolve()-to-self re-verification in load_trusted_skill_dirs, which drops the stale entry rather than following the injected symlink to a directory the user never approved.

Persisted approvals join the containment roots in discover_skills_and_roots, so they apply on subsequent launches. skills trust list|revoke|clear lets users audit and revoke approved directories; the declarative extra_allowed_dirs / env allowlist still works unchanged as the permanent path.

Add an MCP-trust-style approval flow for skills whose SKILL.md resolves
outside trusted skill directories. Instead of a hard PermissionError, the
TUI prompts once to allow the resolved target directory, persists the
decision to ~/.deepagents/.state/skill_trust.json, and retries. Adds
`skills trust list|revoke|clear` to audit and revoke approvals.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
@github-actions github-actions Bot added dcode Related to `deepagents-code` feature New feature/enhancement or request for one internal User is a member of the `langchain-ai` GitHub organization size: L 500-999 LOC labels Jun 24, 2026
@mdrxy
Mason Daugherty (mdrxy) marked this pull request as ready for review June 24, 2026 03:50

@corridor-security corridor-security Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Security Issues

  • Symlink Trust Bypass
    Persisted skill trust entries are resolved again when they are added to the containment roots. If a previously approved directory path is later replaced with a symlink to a different location, the next launch can silently trust the new resolved target without showing the trust prompt, allowing a malicious skill symlink to read files from that new location as skill content.

Comment thread libs/code/deepagents_code/skills/invocation.py Outdated

@open-swe open-swe Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Open SWE Review: No issues found

Open SWE reviewed this PR and found no potential bugs to report.

Open in WebView Open SWE trace

Mason Daugherty (mdrxy) and others added 3 commits July 1, 2026 21:07
Stored skill trust entries are the canonical directory approved by the
user, but discover_skills_and_roots re-resolved them before adding to the
containment allowlist. A post-approval symlink swap of the stored path
(or a parent) would silently allowlist a different target without
re-prompting. Verify each entry still resolves to itself and add the
stored canonical path as-is instead of re-resolving.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Comment thread libs/code/deepagents_code/skills/trust.py Dismissed
@github-actions github-actions Bot added size: XL 1000+ LOC and removed size: L 500-999 LOC labels Jul 6, 2026
Comment thread libs/code/deepagents_code/skills/trust.py Dismissed
Mason Daugherty (mdrxy) and others added 5 commits July 6, 2026 01:54
Restore status.py, test_status.py, version files (0.1.32), CHANGELOG,
release-please-manifest, and lockfiles to match main. These were
unintended regressions carried in by main merge commits.
@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Jul 6, 2026
@mdrxy
Mason Daugherty (mdrxy) merged commit a4431e4 into main Jul 6, 2026
50 of 53 checks passed
@mdrxy
Mason Daugherty (mdrxy) deleted the mdrxy/code/skill-symlink-trust branch July 6, 2026 14:18
Mason Daugherty (mdrxy) added a commit that referenced this pull request Jul 6, 2026
> [!CAUTION]
> Merging this PR will automatically publish to **PyPI** and create a
**GitHub release**.

For the full release process, see
[`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md).

---

_Everything below this line will be the GitHub release body._

---


##
[0.1.33](deepagents-code==0.1.32...deepagents-code==0.1.33)
(2026-07-06)

### Features

* In-the-moment trust prompt for symlinked skills
([#4200](#4200))
([a4431e4](a4431e4))
* Selective per-server project MCP trust
([#4507](#4507))
([aaa22a9](aaa22a9))
* Add `dcode tools list` command
([#4461](#4461))
([1402d0e](1402d0e))

### Bug Fixes

* Strip media placeholders from model-facing message text
([#4462](#4462))
([aa0ae36](aa0ae36))
* Re-apply theme preference on `/reload`
([#4514](#4514))
([5d1c392](5d1c392))

---

_Everything above this line will be the GitHub release body._

---

> [!NOTE]
> A **New Contributors** section is appended to the GitHub release notes
automatically at publish time (see [Release
Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline),
step 2).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dcode Related to `deepagents-code` dependencies Pull requests that update a dependency file feature New feature/enhancement or request for one internal User is a member of the `langchain-ai` GitHub organization size: XL 1000+ LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants