Skip to content
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repository = "https://github.com/zeroclaw-labs/zeroclaw"
readme = "README.md"
keywords = ["ai", "agent", "cli", "assistant", "chatbot"]
categories = ["command-line-utilities", "api-bindings"]
rust-version = "1.87"
rust-version = "1.91"

[dependencies]
# CLI - minimal and fast
Expand Down Expand Up @@ -111,7 +111,7 @@ which = "7.0"

# WebSocket client channels (Discord/Lark/DingTalk)
tokio-tungstenite = { version = "0.28", features = ["rustls-tls-webpki-roots"] }
futures-util = { version = "0.3", default-features = false, features = ["sink"] }
futures-util = { version = "0.3", default-features = false, features = ["sink", "alloc"] }
regex = "1.10"
hostname = "0.4.2"
rustls = "0.23"
Expand Down Expand Up @@ -164,7 +164,7 @@ wa-rs-tokio-transport = { version = "0.2", optional = true, default-features = f
# Raspberry Pi GPIO / Landlock (Linux only) — target-specific to avoid compile failure on macOS
[target.'cfg(target_os = "linux")'.dependencies]
rppal = { version = "0.22", optional = true }
landlock = { version = "0.4", optional = true }
landlock = { version = "0.4" }

# Unix-specific dependencies (for root check, etc.)
[target.'cfg(unix)'.dependencies]
Expand All @@ -183,7 +183,10 @@ browser-native = ["dep:fantoccini"]
# Backward-compatible alias for older invocations
fantoccini = ["browser-native"]
# Sandbox feature aliases used by cfg(feature = "sandbox-*")
sandbox-landlock = ["dep:landlock"]
# sandbox-landlock is now a no-op: landlock compiles automatically on Linux
# (via [target.'cfg(target_os = "linux")'.dependencies]) without requiring a flag.
# Keep for backward compatibility with build scripts that pass --features sandbox-landlock.
sandbox-landlock = []
sandbox-bubblewrap = []
# Backward-compatible alias for older invocations
landlock = ["sandbox-landlock"]
Expand Down
97 changes: 97 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,103 @@ WhatsApp uses Meta's Cloud API with webhooks (push-based, not polling):

6. **Test:** Send a message to your WhatsApp Business number — ZeroClaw will respond via the LLM.

### Security Analysis (2026-02-22)

Full source-code audit of all 31 tool surfaces. Grades reflect the current state of defense-in-depth verified against the implementation.

**Grade scale:** A = strong controls, well-tested · B = adequate controls, gaps identified · C = significant gaps · D = critical issues present

#### File access tools

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `file_read` | Path traversal / probing | **A** | Symlink escape blocked via canonicalization. `record_action()` called pre-canonicalization to prevent timing probes. 10 MB size limit enforced. Comprehensive test coverage including TOCTOU probing. | No action required. |
| `file_write` | Path traversal / TOCTOU | **A-** | Workspace scoping, null-byte rejection, and symlink-target rejection all present. `create_dir_all()` executes before final canonicalization, creating a narrow race window. | Add TOCTOU-specific regression test for directory creation race; consider `O_NOFOLLOW`-equivalent check after creation. |
| `glob_search` | Path traversal / DoS | **A-** | `../` and absolute paths rejected before glob. Resolved paths checked against workspace boundary. MAX_RESULTS = 1000 prevents enumeration DoS. | Acceptable if workspace itself is not a symlink chain. Document assumption in security reference. |
| `pdf_read` | Path traversal / resource exhaustion | **A** | 50 MB limit enforced. Symlink escape blocked. `record_action()` called before canonicalization. CPU-bound extraction offloaded via `spawn_blocking`. | No action required. |
| `image_info` | Path traversal / malformed input | **A-** | 5 MB limit. JPEG segment parsing includes malformed-segment detection. Minor `.exists()` + `metadata()` TOCTOU window is benign for a read-only tool. | No action required. |

#### Network tools

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `http_request` | SSRF | **B+** | Comprehensive private/local IP block-list (IPv4 + IPv6, including link-local and documentation ranges). Domain allowlist with subdomain matching. Sensitive headers redacted in output. Redirect following disabled. | IP check is pre-resolution only; add post-connect re-validation or document egress proxy requirement for high-assurance deployments. |
| `http_request` | Protocol downgrade | **B** | HTTP URLs accepted alongside HTTPS. No operator-level enforcement option. | Add `https_only = true` config key to `SecurityPolicy`; reject plain HTTP unless explicitly opted out. |
| `browser_open` | SSRF-adjacent | **B+** | HTTPS-only enforced at URL validation stage. Same IP block-list as `http_request`. Domain allowlist required. Autonomy and rate-limit gates applied. | Replace manual IPv4 parser with `std::net::IpAddr::parse()` for maintainability. |
| `web_search_tool` | External data injection | **B+** | Query trimmed and validated. DuckDuckGo redirect URLs decoded safely. Brave API key only used when configured. No autonomy gate (read-only by design). | Replace `Regex::new(...).unwrap()` with a lazy static or `OnceLock` to eliminate potential panic on static pattern compilation. |

#### Command execution

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `shell` | Arbitrary command execution / network egress | **B** | Environment cleared before execution; only safe vars (PATH, HOME, TERM, LANG…) re-injected. 60 s timeout + 1 MB output cap. Medium/high-risk commands require `approved = true`. No filtering of network-capable commands (`curl`, `wget`, `nc`). Command validation delegated to runtime adapter — trust boundary is implicit. | Add optional `blocked_commands` list to `SecurityPolicy`. Formalize runtime adapter security contract; add interface-level test. |
| `git_operations` | Injection / unintended exfiltration | **A-** | Comprehensive argument sanitizer blocks `--exec=`, `--upload-pack=`, `-c` config injection, shell metacharacters, backticks, pipes, redirects. Write ops gated on autonomy level. Commit message truncated at 2000 chars (multi-byte safe). | Paths passed via `git add -- {paths}` are sanitized by the argument parser but not independently validated; add an explicit test with path arguments containing special characters. |

#### Memory tools

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `memory_store` / `memory_forget` | Unauthorized mutation | **A** | `enforce_tool_operation(ToolOperation::Act, …)` gate applied. Rate limiting enforced. Memory category validated on write. | No action required. |
| `memory_recall` | Unauthorized read | **A** | Read-only; no autonomy gate needed by design. Result limit cast is safe (saturating math). | No action required. |

#### Agent delegation

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `delegate` | Prompt injection via sub-agent / tool scope creep | **B** | Delegation depth tracked to prevent infinite recursion. Parent tools passed immutably via `Arc`. Sub-agent credential propagation present but trust model not explicitly documented. No validated allowlist preventing unsafe tools (e.g. `shell`, `memory_forget`) from being delegated. | Treat sub-agent output as untrusted data before acting. Define and enforce an explicit tool allowlist for delegated contexts; document the trust boundary in the security reference. |

#### Scheduling

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `cron_add` / `cron_update` / `cron_remove` | Unauthorized schedule mutation | **B+** | `enforce_mutation_allowed()` gate verifies autonomy and rate limits. Feature must be explicitly enabled. Schedule string validated before storage. | Verify that commands stored in cron entries pass through the same sanitization as `shell` tool at execution time. |

#### External API integrations

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `composio` | Credential exposure / SSRF via API | **B** | HTTPS enforced on outbound calls. API key stored via encrypted secret store. Opt-in feature flag. Full execute() path not fully auditable from available context. | Add integration test covering credential non-exposure in error paths. |
| `pushover` | Credential exposure | **B** | Reads `PUSHOVER_TOKEN` and `PUSHOVER_USER_KEY` from `.env` in workspace. If workspace is world-readable, secrets are exposed to any local user. | Move credentials to the encrypted secret store consistent with other integrations; document workspace permission requirements in the runbook. |
| `proxy_config` | Unauthorized config mutation | **B+** | Config reloaded without environment variables to prevent env override leakage. Write access gated. `ProxyScope` input normalized. | No critical gaps identified; full audit recommended before production use. |

#### Utility tools

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `screenshot` | Shell injection via filename | **B+** | Filename sanitized (directory components stripped, shell-unsafe chars rejected) before interpolation into shell command string. Autonomy gated. 2 MB base64 limit enforced. | Refactor Linux branch to use array-based command construction (avoid string interpolation into shell) to eliminate the dependency on correct prior sanitization. |
| `image_info` | Malformed binary parsing | **A-** | Magic-byte format detection. JPEG segment parsing with malformed-segment detection. Workspace boundary enforced. | No critical action required. |

#### Hardware tools

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `hardware_memory_read` / `hardware_memory_map` | Direct memory access | **B** | Peripheral access is trait-gated; tools delegate to hardware abstraction layer. Address range bounds and alignment validation not visible at tool layer — must be enforced by peripheral implementation. | Audit peripheral implementations for explicit address-range allow-lists and read-size limits before enabling in production. Document hardware trust boundary in `docs/hardware-peripherals-design.md`. |
| `hardware_board_info` | Information disclosure | **B+** | Board metadata read-only. Risk is low if hardware identity is not considered sensitive in the deployment context. | Confirm output does not expose firmware secrets or debug interfaces in production board configs. |

#### Compiler hygiene

| Surface | Risk area | Grade | Finding | Recommended action |
|---|---|:---:|---|---|
| `src/security/mod.rs` / `src/tools/mod.rs` | Compiler signal degradation | **B+** | Multiple `#[allow(unused_imports)]` suppress warnings in security-critical modules, reducing the reliability of `cargo clippy -D warnings` as a regression signal. | Remove dead imports and the corresponding `#[allow]` suppressions; keep compiler output clean as a CI gate. |

#### Overall posture

| Tier | Coverage | Grade |
|---|---|:---:|
| File access | `file_read`, `file_write`, `glob_search`, `pdf_read`, `image_info` | **A-** |
| Network | `http_request`, `browser_open`, `web_search_tool` | **B+** |
| Command execution | `shell`, `git_operations` | **B+** |
| Memory | `memory_store`, `memory_recall`, `memory_forget` | **A** |
| Delegation | `delegate` | **B** |
| Scheduling | `cron_*`, `schedule` | **B+** |
| External APIs | `composio`, `pushover`, `proxy_config` | **B** |
| Utility | `screenshot`, `image_info` | **B+** |
| Hardware | `hardware_memory_read`, `hardware_memory_map`, `hardware_board_info` | **B** |
| Compiler hygiene | `src/security/`, `src/tools/` | **B+** |
| **Repository overall** | 31 surfaces audited | **B+** |

> Full security model and configuration reference: [docs/security/README.md](docs/security/README.md)

## Configuration

Config: `~/.zeroclaw/config.toml` (created by `onboard`)
Expand Down
3 changes: 2 additions & 1 deletion benches/agent_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
//!
//! Ref: https://github.com/zeroclaw-labs/zeroclaw/issues/618 (item 7)
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use criterion::{criterion_group, criterion_main, Criterion};
use std::hint::black_box;
use std::sync::{Arc, Mutex};

use zeroclaw::agent::agent::Agent;
Expand Down
21 changes: 19 additions & 2 deletions docs/channels-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ ignore_stories = true

ZeroClaw supports two WhatsApp backends:

- **Cloud API mode** (`phone_number_id` + `access_token` + `verify_token`)
- **WhatsApp Web mode** (`session_path`, requires build flag `--features whatsapp-web`)
- **Cloud API mode** (`phone_number_id` + `access_token` + `verify_token`) — stable, uses the official Meta Cloud API.
- **WhatsApp Web mode** (`session_path`, requires build flag `--features whatsapp-web`) — **experimental, see security warning below**.

Cloud API mode:

Expand All @@ -242,9 +242,26 @@ pair_code = "" # optional custom pair code
allowed_numbers = ["*"]
```

> **Security warning — WhatsApp Web mode (`--features whatsapp-web`)**
>
> WhatsApp Web mode uses the `wa-rs` library, which reverse-engineers the
> WhatsApp Web protocol. This approach carries risks that do not apply to the
> Cloud API mode:
>
> - **Unofficial API:** The protocol is not documented or supported by Meta.
> It can break without notice on any WhatsApp update.
> - **Account risk:** Meta may suspend accounts detected using unofficial clients.
> - **Unpredictable attack surface:** Protocol changes or undocumented behaviors
> can introduce security regressions that are hard to audit or anticipate.
> - **Recommended only for:** controlled, non-production environments where the
> Cloud API is unavailable and account suspension is acceptable.
>
> For production deployments, the Cloud API mode is strongly preferred.

Notes:

- Build with `cargo build --features whatsapp-web` (or equivalent run command).
The feature is disabled by default. Prefer Cloud API mode in production.
- Keep `session_path` on persistent storage to avoid relinking after restart.
- Reply routing uses the originating chat JID, so direct and group replies work correctly.

Expand Down
2 changes: 2 additions & 0 deletions docs/security/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ For current runtime behavior, start here:
- Config reference: [../config-reference.md](../config-reference.md)
- Operations runbook: [../operations-runbook.md](../operations-runbook.md)
- Troubleshooting: [../troubleshooting.md](../troubleshooting.md)
- SSRF threat model (http_request tool): [http-request-ssrf-threat-model.md](http-request-ssrf-threat-model.md)
- Shell execution security note: [shell-execution-security-note.md](shell-execution-security-note.md)

## Proposal / Roadmap Docs

Expand Down
Loading