* fix: safety guard incorrectly blocks commands with URLs
The absolutePathPattern regex was matching URL path components like
//github.com as file system paths, causing commands containing URLs
to be incorrectly blocked by the workspace restriction safety guard.
For example, 'agent-browser open https://github.com' would be blocked
because //github.com was treated as an absolute file path outside
the working directory.
The fix adds a check to skip any path match that starts with '//',
as these are URL path components, not file system paths.
Fixes#1203
* fix: handle file:// URIs correctly in safety guard
The previous fix skipped all paths starting with '//', which incorrectly
also skipped file:// URIs that could escape the workspace sandbox.
Changes:
- Only skip '//' paths when preceded by web URL schemes (http:, https:, ftp:, etc.)
- file:// URIs are now properly checked against workspace boundaries
- Added TestShellTool_FileURISandboxing to verify the fix
Fixes security issue raised by @alexhoshina in PR #1254
* style: fix gofumpt formatting
* fix(safety-guard): use exact match position to prevent URL exemption bypass
Using strings.Index(cmd, raw) always returned the first occurrence of the
matched substring, allowing a bypass where the same //path appeared both
inside a URL and as a standalone shell path (e.g. echo https://etc/passwd
&& cat //etc/passwd would skip the second match).
Switch to FindAllStringIndex so each match is evaluated at its actual
position in the command string.
Adds TestShellTool_URLBypassPrevented to cover the exploit scenario.
* fix(tools): allow /dev/null redirection and add read/write sandbox split
- Remove deny pattern that incorrectly blocked redirects to /dev/null
- Expand block device write pattern to cover nvme, mmcblk, vd, xvd,
hd, loop, dm-, md, sr and nbd in addition to sd
- Add safe path whitelist for kernel pseudo-devices so workspace path
check does not reject /dev/null, /dev/zero, /dev/random, /dev/urandom,
/dev/stdin, /dev/stdout and /dev/stderr
- Add allow_read_outside_workspace config option (default true) so file
read and list tools are unrestricted while write tools stay sandboxed
Closes https://github.com/sipeed/picoclaw/issues/964
Closes https://github.com/sipeed/picoclaw/issues/965
Signed-off-by: Huang Rui <vowstar@gmail.com>
* feat(tools): add configurable allow patterns and path whitelists
- Add custom_allow_patterns to exec config so users can exempt specific
commands from deny pattern checks
- Add allow_read_paths and allow_write_paths regex lists to tools config
for whitelisting specific paths outside the workspace
- Introduce whitelistFs that wraps sandboxFs and falls through to hostFs
for paths matching whitelist patterns
- Use variadic constructor signatures to keep backward compatibility
Suggested-by: lxowalle
Signed-off-by: Huang Rui <vowstar@gmail.com>
---------
Signed-off-by: Huang Rui <vowstar@gmail.com>
Resolved conflicts:
- pkg/heartbeat/service.go: merged both 'started' field and 'onHeartbeatWithTools'
- pkg/tools/edit.go: use validatePath() with ToolResult return
- pkg/tools/filesystem.go: fixed return values to use ToolResult
- cmd/picoclaw/main.go: kept active setupCronTool, fixed toolsPkg import
- pkg/tools/cron.go: fixed Execute return value handling
Fixed tests for new function signatures (NewEditFileTool, NewAppendFileTool, NewExecTool)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>