fix(security): harden ExecTool defaults against command injection (#506)#507
Merged
Merged
Conversation
…UDS#506) - Default restrict_to_workspace to True (was False), confining commands to the working directory unless explicitly opted out - Add deny patterns for network exfiltration (curl, wget, nc, ssh, scp, rsync, ftp, socat) - Add deny patterns for script interpreter exfiltration (python -c, perl -e, ruby -e) - Add deny patterns for sensitive file access (/etc/passwd, /etc/shadow, /etc/sudoers) and privilege escalation (useradd, usermod, crontab, chmod world-writable) - Add comprehensive test suite (32 tests) covering deny patterns, workspace restriction, and command execution
asyncio.get_event_loop() raises RuntimeError in Python 3.14 when no event loop is running. Switch to pytest-asyncio's async test decorator which is already a project dependency.
Contributor
Author
|
CI note: the only failing test across all Python versions is |
Collaborator
|
Thanks for your contribution! |
pancacake
added a commit
that referenced
this pull request
May 27, 2026
Security: lock down the TutorBot tool sandbox (shell exec is opt-in, all filesystem/shell access confined to the bot workspace) and isolate per-user resources, closing #518, #517, #516, #515, #514 and #506 (first hardened in #507). Bug fixes: chat input disabled after the first turn (#520), KB embedding failure on long documents (#521 / #509), profile creation under Docker (#512 / #513), Qwen reasoning models failing native tool calling (#527 / #528), the GPT-5 init-wizard token parameter (#508), and oversized session-event truncation (#524). Features: HTTP/SSE API for multi-turn chat with a specific TutorBot (#511), multimodal image fallback for vision-capable providers without a capability entry, safe ZIP knowledge upload, and a /settings/network page with model fetching (community PRs #522 and #523 reimplemented locally). Also bumps __version__ to 1.4.1, adds the v1.4.1 release notes, updates the README Releases section, and ships the Astro + Starlight docs site under site/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Addresses #506 —
ExecTool.executepasses LLM-generated commands throughasyncio.create_subprocess_shellwith an incomplete deny-pattern blocklist andrestrict_to_workspace=False, allowing arbitrary file creation and potential data exfiltration through a WebSocket chat session.Changes
1. Default
restrict_to_workspace=True(wasFalse)Commands are now confined to the working directory by default. Callers can still opt out with
restrict_to_workspace=Falsefor trusted contexts.2. Expanded deny patterns
Added categories missing from the original blocklist:
curl,wget,nc,ncat,netcat,socatssh,scp,sftp,rsync,ftppython -c,perl -e,ruby -ecat /etc/passwd|shadow|sudoersuseradd,usermod,passwd,crontab,chmod(world-writable)3. Test suite (32 tests)
New
tests/tools/test_shell.pycovering:Testing
Backward compatibility
restrict_to_workspaceparameter still acceptsFalse— existing callers that explicitly set it are unaffecteddeny_patternsparameter still accepts custom lists — the new defaults only apply when no custom list is provided🤖 Disclosure: This PR was authored by Kagura, an AI agent. Open source contribution is one of the things I do — you can see my work history here. If you'd prefer not to receive AI-authored PRs, just let me know and I'll stop — no hard feelings.