Documentation Index
Fetch the complete documentation index at: https://mintlify.com/sipeed/picoclaw/llms.txt
Use this file to discover all available pages before exploring further.
Overview
PicoClaw implements a multi-layered security architecture to protect your system while allowing AI agents to perform useful tasks. The security model focuses on workspace isolation, command filtering, and path validation.
Workspace Sandbox
The primary security mechanism is workspace restriction, which isolates agent file and command access to a configured directory.
Default Configuration
{
"agents": {
"defaults": {
"workspace": "~/.picoclaw/workspace",
"restrict_to_workspace": true // Default: enabled
}
}
}
| Option | Type | Default | Description |
|---|
workspace | string | ~/.picoclaw/workspace | Agent workspace directory |
restrict_to_workspace | bool | true | Sandbox all file/shell operations |
allow_read_outside_workspace | bool | false | Allow reading outside workspace |
When restrict_to_workspace: true, the following tools are sandboxed:
| Tool | Function | Restriction |
|---|
read_file | Read files | Only files within workspace |
write_file | Write files | Only files within workspace |
list_dir | List directories | Only directories within workspace |
edit_file | Edit files | Only files within workspace |
append_file | Append to files | Only files within workspace |
exec | Execute commands | Command paths validated against workspace |
How Workspace Restriction Works
Path Resolution
All file paths are resolved and validated before access:
User input: "./data/config.json"
↓
Resolve relative to workspace
↓
Absolute path: "/home/user/.picoclaw/workspace/data/config.json"
↓
Validate: Is within workspace?
↓
Yes → Allow access
No → Deny with error
Implementation
From pkg/tools/filesystem.go:
func validatePath(path, workspace string, restrict bool) (string, error) {
// 1. Resolve to absolute path
absPath := filepath.Abs(filepath.Join(workspace, path))
// 2. Check if restrict is enabled
if !restrict {
return absPath, nil
}
// 3. Validate path is within workspace
if !isWithinWorkspace(absPath, workspace) {
return "", fmt.Errorf("access denied: path is outside the workspace")
}
// 4. Check for symlink escapes
resolved, err := filepath.EvalSymlinks(absPath)
if err == nil && !isWithinWorkspace(resolved, workspace) {
return "", fmt.Errorf("access denied: symlink resolves outside workspace")
}
return absPath, nil
}
Sandbox Implementations
sandboxFs (Go 1.23+)
Uses os.Root for kernel-level path isolation:
type sandboxFs struct {
workspace string
}
func (r *sandboxFs) ReadFile(path string) ([]byte, error) {
root, err := os.OpenRoot(r.workspace)
if err != nil {
return nil, err
}
defer root.Close()
// All operations scoped to root
return root.ReadFile(path)
}
Security:
- Kernel-enforced path isolation
- Immune to
../ traversal
- Symlinks cannot escape root
- No
chroot required
hostFs (Unrestricted)
Direct filesystem access when restrict_to_workspace: false:
type hostFs struct{}
func (h *hostFs) ReadFile(path string) ([]byte, error) {
return os.ReadFile(path) // No restrictions
}
⚠️ Warning: Only disable restrictions in controlled environments.
Path Whitelisting
Allow specific paths outside workspace using regex patterns.
Configuration
{
"tools": {
"allow_read_paths": [
"^/etc/hosts$",
"^/proc/cpuinfo$",
"^/sys/class/net/[^/]+/address$"
],
"allow_write_paths": [
"^/tmp/picoclaw-.*\.txt$"
]
}
}
Pattern Syntax
Regular expressions matched against absolute paths:
| Pattern | Matches | Examples |
|---|
^/etc/hosts$ | Exact path | /etc/hosts |
^/proc/.* | Prefix | /proc/cpuinfo, /proc/meminfo |
^/tmp/.*\.log$ | Suffix | /tmp/app.log, /tmp/error.log |
^/sys/class/net/[^/]+/address$ | Pattern | /sys/class/net/eth0/address |
whitelistFs Implementation
Combines sandbox with selective host access:
type whitelistFs struct {
sandbox *sandboxFs
host hostFs
patterns []*regexp.Regexp
}
func (w *whitelistFs) ReadFile(path string) ([]byte, error) {
// Check if path matches whitelist
if w.matches(path) {
return w.host.ReadFile(path) // Host access
}
return w.sandbox.ReadFile(path) // Sandboxed access
}
Use Cases
System monitoring:
{
"allow_read_paths": [
"^/proc/loadavg$",
"^/proc/meminfo$",
"^/proc/cpuinfo$"
]
}
Network config:
{
"allow_read_paths": [
"^/etc/resolv\.conf$",
"^/etc/hosts$"
]
}
Temporary files:
{
"allow_write_paths": [
"^/tmp/picoclaw-[0-9a-f]{8}.*$"
]
}
The exec tool has multiple layers of protection to prevent dangerous commands.
1. Dangerous Pattern Blocking
From pkg/tools/shell.go, these patterns are blocked by default:
Destructive Commands
\brm\s+-[rf]{1,2}\b # rm -rf, rm -r, rm -f
\bdel\s+/[fq]\b # del /f, del /q (Windows)
\brmdir\s+/s\b # rmdir /s (Windows)
\b(format|mkfs|diskpart)\b\s # Disk formatting
\bdd\s+if= # dd (disk imaging)
>/dev/(sd[a-z]|hd[a-z]|...) # Direct disk writes
System Control
\b(shutdown|reboot|poweroff)\b # System shutdown
Shell Injection
:\(\)\s*\{.*\};\s*: # Fork bomb
\$\([^)]+\) # Command substitution
\$\{[^}]+\} # Variable expansion
`[^`]+` # Backtick execution
\|\s*sh\b # Pipe to shell
\|\s*bash\b
Privilege Escalation
\bsudo\b # Sudo
\bchmod\s+[0-7]{3,4}\b # chmod
\bchown\b # chown
Process Control
\bpkill\b # pkill
\bkillall\b # killall
\bkill\s+-[9]\b # kill -9
Remote Execution
\bcurl\b.*\|\s*(sh|bash) # curl | sh
\bwget\b.*\|\s*(sh|bash) # wget | sh
\bssh\b.*@ # SSH connections
Package Managers
\bapt\s+(install|remove|purge)\b
\byum\s+(install|remove)\b
\bdnf\s+(install|remove)\b
\bnpm\s+install\s+-g\b
\bpip\s+install\s+--user\b
Containers
\bdocker\s+run\b
\bdocker\s+exec\b
Version Control
\bgit\s+push\b
\bgit\s+force\b
2. Workspace Path Validation
When restrict_to_workspace: true, absolute paths in commands are validated:
# Workspace: /home/user/.picoclaw/workspace
# Allowed:
ls ./data # OK (relative)
cat /home/user/.picoclaw/workspace/file.txt # OK (within workspace)
echo "test" > output.txt # OK (relative)
# Blocked:
cat /etc/passwd # BLOCKED (outside workspace)
ls /home/user/documents # BLOCKED (outside workspace)
cp ../../../etc/passwd . # BLOCKED (path traversal)
Implementation:
func (t *ExecTool) guardCommand(command, cwd string) string {
// Extract absolute paths from command
matches := absolutePathPattern.FindAllString(command, -1)
for _, path := range matches {
// Skip safe paths
if safePaths[path] {
continue
}
// Validate path is within workspace
rel, err := filepath.Rel(cwd, path)
if err != nil || strings.HasPrefix(rel, "..") {
return "Command blocked by safety guard (path outside working dir)"
}
}
return "" // OK
}
3. Safe Paths
These kernel pseudo-devices are always allowed:
var safePaths = map[string]bool{
"/dev/null": true,
"/dev/zero": true,
"/dev/random": true,
"/dev/urandom": true,
"/dev/stdin": true,
"/dev/stdout": true,
"/dev/stderr": true,
}
4. Custom Patterns
Override or extend default patterns:
{
"tools": {
"exec": {
"enable_deny_patterns": true,
"custom_deny_patterns": [
"\\bcurl\\b.*--upload-file",
"\\bwget\\b.*-O\\s+/etc/"
],
"custom_allow_patterns": [
"^git\\s+push\\s+origin\\s+main$"
]
}
}
}
Behavior:
custom_allow_patterns: Bypass deny patterns for specific commands
custom_deny_patterns: Additional blocks beyond defaults
enable_deny_patterns: false: Disable all pattern checks (⚠️ dangerous)
5. Execution Timeout
Prevents infinite execution:
type ExecTool struct {
timeout time.Duration // Default: 60s
}
Configuration:
{
"tools": {
"cron": {
"exec_timeout_minutes": 5 // 5 minutes for scheduled tasks
}
}
}
6. Process Tree Termination
Kills child processes on timeout (Unix):
func terminateProcessTree(cmd *exec.Cmd) error {
// Send SIGTERM to process group
pgid, err := syscall.Getpgid(cmd.Process.Pid)
syscall.Kill(-pgid, syscall.SIGTERM)
// Wait 2s, then SIGKILL if still running
time.Sleep(2 * time.Second)
syscall.Kill(-pgid, syscall.SIGKILL)
}
Security Boundaries
Consistent Across Execution Paths
The same security restrictions apply everywhere:
| Execution Path | Workspace Restriction | Exec Guards |
|---|
| Main Agent | ✅ | ✅ |
| Subagent (spawn) | ✅ Inherited | ✅ Inherited |
| Heartbeat tasks | ✅ Inherited | ✅ Inherited |
| Cron jobs | ✅ Inherited | ✅ Inherited |
No bypass possible through subagents or scheduled tasks.
Multi-Agent Isolation
Each agent has its own workspace:
~/.picoclaw/workspace/ # Agent: main
~/.picoclaw/workspace-researcher/ # Agent: researcher
~/.picoclaw/workspace-coder/ # Agent: coder
Isolation:
- File operations scoped to agent workspace
- Sessions isolated per agent
- No cross-agent file access
Error Messages
File Access Denied
[ERROR] tool: Tool execution failed
{tool=read_file, error=access denied: path is outside the workspace}
[ERROR] tool: Tool execution failed
{tool=write_file, error=access denied: symlink resolves outside workspace}
Command Blocked
[ERROR] tool: Tool execution failed
{tool=exec, error=Command blocked by safety guard (dangerous pattern detected)}
[ERROR] tool: Tool execution failed
{tool=exec, error=Command blocked by safety guard (path outside working dir)}
Path Traversal
[ERROR] tool: Tool execution failed
{tool=read_file, error=access denied: path is outside the workspace}
Disabling Restrictions (⚠️ Dangerous)
Method 1: Config File
{
"agents": {
"defaults": {
"restrict_to_workspace": false
}
}
}
Method 2: Environment Variable
export PICOCLAW_AGENTS_DEFAULTS_RESTRICT_TO_WORKSPACE=false
picoclaw agent
Method 3: Disable Exec Patterns Only
{
"tools": {
"exec": {
"enable_deny_patterns": false
}
}
}
⚠️ Security Warning:
Disabling restrictions allows the agent to:
- Access any file on your system
- Execute any command
- Modify system files
- Install packages
- Access sensitive data
Only disable in:
- Isolated development environments
- Containers with limited host access
- Trusted, controlled scenarios
Best Practices
1. Keep Sandbox Enabled
Always use restrict_to_workspace: true unless absolutely necessary.
2. Use Path Whitelisting
Instead of disabling sandbox, whitelist specific paths:
{
"tools": {
"allow_read_paths": ["^/etc/hosts$"]
}
}
3. Review Custom Patterns
Carefully test custom allow patterns:
{
"tools": {
"exec": {
"custom_allow_patterns": [
"^git\\s+push\\s+origin\\s+(main|develop)$" // Specific branches only
]
}
}
}
4. Use Separate Workspaces
Isolate agents by task:
{
"agents": {
"agents": [
{"id": "main", "workspace": "~/.picoclaw/workspace"},
{"id": "untrusted", "workspace": "/tmp/picoclaw-sandbox"}
]
}
}
5. Monitor Agent Actions
Enable debug logging to audit agent commands:
export PICOCLAW_LOG_LEVEL=debug
picoclaw agent
Disable unnecessary tools for specific agents:
{
"agents": {
"agents": [
{
"id": "readonly",
"tools": {
"disabled": ["write_file", "exec", "edit_file"]
}
}
]
}
}
7. Container Isolation
Run PicoClaw in containers with limited host access:
FROM golang:1.23
RUN useradd -m -s /bin/bash picoclaw
USER picoclaw
WORKDIR /home/picoclaw
COPY picoclaw /usr/local/bin/
CMD ["picoclaw", "gateway"]
8. Principle of Least Privilege
- Start with full restrictions
- Add whitelisted paths as needed
- Document all exceptions
- Review periodically
Security Checklist
Reporting Security Issues
If you discover a security vulnerability in PicoClaw:
- Do not open a public issue
- Email security details to the maintainers
- Include reproduction steps
- Wait for confirmation before public disclosure
See project README for contact information.