diff --git a/Dockerfile b/Dockerfile index dd98ec0bd..0360cfda6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,7 +29,14 @@ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ # Copy binary COPY --from=builder /src/build/picoclaw /usr/local/bin/picoclaw -# Create picoclaw home directory +# Create non-root user and group +RUN addgroup -g 1000 picoclaw && \ + adduser -D -u 1000 -G picoclaw picoclaw + +# Switch to non-root user +USER picoclaw + +# Run onboard to create initial directories and config RUN /usr/local/bin/picoclaw onboard ENTRYPOINT ["picoclaw"] diff --git a/docker-compose.yml b/docker-compose.yml index 48769627c..32e8ee339 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,8 +11,8 @@ services: profiles: - agent volumes: - - ./config/config.json:/root/.picoclaw/config.json:ro - - picoclaw-workspace:/root/.picoclaw/workspace + - ./config/config.json:/home/picoclaw/.picoclaw/config.json:ro + - picoclaw-workspace:/home/picoclaw/.picoclaw/workspace entrypoint: ["picoclaw", "agent"] stdin_open: true tty: true @@ -31,9 +31,9 @@ services: - gateway volumes: # Configuration file - - ./config/config.json:/root/.picoclaw/config.json:ro + - ./config/config.json:/home/picoclaw/.picoclaw/config.json:ro # Persistent workspace (sessions, memory, logs) - - picoclaw-workspace:/root/.picoclaw/workspace + - picoclaw-workspace:/home/picoclaw/.picoclaw/workspace command: ["gateway"] volumes: diff --git a/pkg/tools/shell.go b/pkg/tools/shell.go index 713850f97..9c82b2748 100644 --- a/pkg/tools/shell.go +++ b/pkg/tools/shell.go @@ -31,6 +31,40 @@ func NewExecTool(workingDir string, restrict bool) *ExecTool { regexp.MustCompile(`>\s*/dev/sd[a-z]\b`), // Block writes to disk devices (but allow /dev/null) regexp.MustCompile(`\b(shutdown|reboot|poweroff)\b`), regexp.MustCompile(`:\(\)\s*\{.*\};\s*:`), + regexp.MustCompile(`\$\([^)]+\)`), + regexp.MustCompile(`\$\{[^}]+\}`), + regexp.MustCompile("`[^`]+`"), + regexp.MustCompile(`\|\s*sh\b`), + regexp.MustCompile(`\|\s*bash\b`), + regexp.MustCompile(`;\s*rm\s+-[rf]`), + regexp.MustCompile(`&&\s*rm\s+-[rf]`), + regexp.MustCompile(`\|\|\s*rm\s+-[rf]`), + regexp.MustCompile(`>\s*/dev/null\s*>&?\s*\d?`), + regexp.MustCompile(`<<\s*EOF`), + regexp.MustCompile(`\$\(\s*cat\s+`), + regexp.MustCompile(`\$\(\s*curl\s+`), + regexp.MustCompile(`\$\(\s*wget\s+`), + regexp.MustCompile(`\$\(\s*which\s+`), + regexp.MustCompile(`\bsudo\b`), + regexp.MustCompile(`\bchmod\s+[0-7]{3,4}\b`), + regexp.MustCompile(`\bchown\b`), + regexp.MustCompile(`\bpkill\b`), + regexp.MustCompile(`\bkillall\b`), + regexp.MustCompile(`\bkill\s+-[9]\b`), + regexp.MustCompile(`\bcurl\b.*\|\s*(sh|bash)`), + regexp.MustCompile(`\bwget\b.*\|\s*(sh|bash)`), + regexp.MustCompile(`\bnpm\s+install\s+-g\b`), + regexp.MustCompile(`\bpip\s+install\s+--user\b`), + regexp.MustCompile(`\bapt\s+(install|remove|purge)\b`), + regexp.MustCompile(`\byum\s+(install|remove)\b`), + regexp.MustCompile(`\bdnf\s+(install|remove)\b`), + regexp.MustCompile(`\bdocker\s+run\b`), + regexp.MustCompile(`\bdocker\s+exec\b`), + regexp.MustCompile(`\bgit\s+push\b`), + regexp.MustCompile(`\bgit\s+force\b`), + regexp.MustCompile(`\bssh\b.*@`), + regexp.MustCompile(`\beval\b`), + regexp.MustCompile(`\bsource\s+.*\.sh\b`), } return &ExecTool{