Skip to content

feat(sdk): add permissions system for filesystem access control#2633

Merged
Nick Hollon (nick-hollon-lc) merged 9 commits intomainfrom
nh/enforce-filesystem-policies
Apr 10, 2026
Merged

feat(sdk): add permissions system for filesystem access control#2633
Nick Hollon (nick-hollon-lc) merged 9 commits intomainfrom
nh/enforce-filesystem-policies

Conversation

@nick-hollon-lc
Copy link
Copy Markdown
Contributor

@nick-hollon-lc Nick Hollon (nick-hollon-lc) commented Apr 9, 2026

Examples

Read-only agent (no writes anywhere):

agent = create_deep_agent(
    permissions=[
        FilesystemPermission(operations=["write"], paths=["/**"], mode="deny"),
    ]
)

Sandbox the agent to a workspace directory:

agent = create_deep_agent(
    permissions=[
        FilesystemPermission(operations=["read", "write"], paths=["/workspace/**"], mode="allow"),
        FilesystemPermission(operations=["read", "write"], paths=["/**"], mode="deny"),
    ]
)

Protect examples while allowing broad access:

agent = create_deep_agent(
    permissions=[
        FilesystemPermission(operations=["read", "write"], paths=["/workspace/.env", "/workspace/examples/**"], mode="deny"),
        FilesystemPermission(operations=["read", "write"], paths=["/workspace/**"], mode="allow"),
    ]
)

Subagent with tighter permissions than the parent:

agent = create_deep_agent(
    permissions=[
        FilesystemPermission(operations=["read", "write"], paths=["/workspace/**"], mode="allow"),
        FilesystemPermission(operations=["read", "write"], paths=["/**"], mode="deny"),
    ],
    subagents=[
        {
            "name": "auditor",
            "description": "Read-only code reviewer",
            "system_prompt": "Review the code for issues.",
            "permissions": [
                FilesystemPermission(operations=["write"], paths=["/**"], mode="deny"),
                FilesystemPermission(operations=["read"], paths=["/workspace/**"], mode="allow"),
                FilesystemPermission(operations=["read"], paths=["/**"], mode="deny"),
            ],
        }
    ],
)

What it enforces

  • Pre-check: blocks calls to the six built-in filesystem tools (ls, read_file, glob, grep, write_file, edit_file) when the canonicalized path matches a deny rule. Paths are resolved via validate_path() to prevent traversal bypasses.
  • Post-filter: after execution, filters denied paths out of ls, glob, and grep results using ToolMessage.artifact (the structured backend result object), then rebuilds the content string.
  • Rule evaluation: first-match-wins in declaration order; permissive default (allow if no rule matches).
  • Subagent inheritance: subagents inherit the parent's permissions by default. A subagent can specify its own permissions field, which replaces the parent's rules entirely.
  • PermissionMiddleware is placed last in the middleware stack so it sees all tools (including those injected by other middleware).

What it does not enforce

  • execute tool: shell commands can trivially bypass filesystem restrictions. Rather than silently failing, the middleware raises NotImplementedError at init if the backend supports execution.
  • User-provided or MCP tools: only the six built-in filesystem tool names are intercepted. Custom tools that access the filesystem are not covered.
  • Tool-level permissions: an earlier iteration explored ToolPermission rules but they were deferred — pattern-matching tool arguments with globs is unsafe for shell commands and type coercion of non-string args is a footgun.

Introduce `FilesystemPermission` and `ToolPermission` dataclasses with
first-match-wins evaluation and glob pattern matching via wcmatch.
`FilesystemMiddleware` enforces path-level read/write rules;
`ToolPermissionMiddleware` enforces tool-level rules at the
`wrap_tool_call` boundary. Subagents inherit parent permissions unless
they specify their own.

Also fixes grep tool missing `validate_path` call on its path argument,
which previously allowed path traversal bypasses on grep specifically.
@github-actions github-actions bot added deepagents Related to the `deepagents` SDK / agent harness feature New feature/enhancement or request for one internal User is a member of the `langchain-ai` GitHub organization size: XL 1000+ LOC labels Apr 9, 2026
Copy link
Copy Markdown
Member

@hntrl Hunter Lovell (hntrl) left a comment

Choose a reason for hiding this comment

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

nice work!

Comment on lines +73 to +74
# Disable a tool entirely
ToolPermission(name="execute", mode="deny")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

would our guidance be to just remove the tool entirely? (e.g. configurability)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

not sure i totally uderstand this question. just an example of disabling a tool completely here

from deepagents.permissions import ToolPermission

# Allow only pytest invocations, deny everything else
ToolPermission(name="execute", args={"command": "pytest *"})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is this just intended for pattern matching on basic tool call args? What happens if I have a tool schema thats not just dict[str, str]?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah just for basic args. it will stringify the arg before attempting the comparison

…ything. use artifacts on tool message to pass out enough info for post filtering in the permission middleware
@nick-hollon-lc Nick Hollon (nick-hollon-lc) changed the title feat(sdk): add permissions system for filesystem and tool access control feat(sdk): add permissions system for filesystem access control Apr 9, 2026
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

excited about this!! great work, approving pending comments are addressed

fast follows -- return ToolMessage from all filesystem tools + status of error instead of just error strings for relevant cases

figure out what we're doing for ToolPermissions + execute stuff

…f error when we fail because permission denied
@eyurtsev
Copy link
Copy Markdown
Collaborator

OK this looks pretty good!

  • minor refactor with respect to permission.py file (merge it with middleware)
  • pr description

@nick-hollon-lc Nick Hollon (nick-hollon-lc) merged commit 41dc759 into main Apr 10, 2026
33 checks passed
@nick-hollon-lc Nick Hollon (nick-hollon-lc) deleted the nh/enforce-filesystem-policies branch April 10, 2026 14:25
Mason Daugherty (mdrxy) added a commit that referenced this pull request Apr 10, 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.5.2](deepagents==0.5.1...deepagents==0.5.2)
(2026-04-10)

### Features

* Permissions system for filesystem access control
([#2633](#2633))
([41dc759](41dc759))
* Scope permissions to routes for composite backends with sandbox
default
([#2659](#2659))
([6dd6122](6dd6122))
* Raise `ValueError` for permission paths without leading slash and path
traversal
([#2665](#2665))
([723d27d](723d27d))
* Implement `upload_files` for `StateBackend`
([#2661](#2661))
([5798345](5798345))

### Bug Fixes

* Catch `PermissionError` in `FilesystemBackend` ripgrep
([#2571](#2571))
([3d5d673](3d5d673))

---

_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

deepagents Related to the `deepagents` SDK / agent harness 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.

5 participants