Skip to content

Security Limitations — What We Do Not (Yet) Enforce

PersonalClaw’s strongest claim is that its controls are enforced at the point of execution, not merely requested in a prompt. Honesty requires naming the places where that is not (yet) literally true. These are deliberate, documented tradeoffs — not oversights — and each is stated here in the same terms the internal architecture uses, without softening.

This page is referenced from the public threat model and from SECURITY.md. Verified against the codebase at the commit that introduced this file.

1. ACP agents under auto-approve (YOLO) rely on system-prompt framing, not rails

Section titled “1. ACP agents under auto-approve (YOLO) rely on system-prompt framing, not rails”

Task modes (agent / ask / plan / build) decide which tools may run. For the native runtime, this gate is hard-enforced: task_modes.py is enforced in _guard_and_invoke before approval is consulted, so a Trust/YOLO auto-approve can never bypass a task-mode restriction (src/personalclaw/task_modes.py).

For ACP agents (external CLI agents driven over the Agent Client Protocol), the same module is applied in the dashboard’s permission handler as “belt-and-suspenders for ACP runtimes that gate via their own protocol path” (task_modes.py). But an ACP agent running under YOLO ultimately gates through its own protocol path, and the architecture states the tradeoff plainly:

Task-mode tool-gating postures are hard-enforced at the permission prompt for the native runtime; ACP agents under YOLO rely on system-prompt framing (a documented tradeoff — task_modes.py). — docs/architecture/security.md

What this means for you: if you enable auto-approve (YOLO) and run an external ACP agent, that agent’s tool use is bounded by prompt framing rather than by the same hard rail the native runtime enforces. Running a trusted native agent, or leaving approval prompts on, keeps the hard rail in force.

2. The app network permission is declaration-only

Section titled “2. The app network permission is declaration-only”

An app manifest declares a permission scope (api / events / mcpTools / storage / network / memory / cron). Most of these are enforced server-side by the gateway. network is not, by design:

can_use_networkDECLARATION-ONLY (unenforced by design). An app backend is an isolated subprocess with its own OS-level network stack; there is no in-process egress hook the gateway can intercept. The flag records INTENT so the Store can surface it (install consent lists “network access: yes/no”) and a future OS-level isolation layer (cgroups/nftables/seccomp) can enforce it. Every gateway-MEDIATED reach is already bounded by can_use_api — a network:false app can still reach the internet through its own subprocess … Until then, treat network: true as an honest declaration, not a security boundary. — src/personalclaw/apps/permissions.py

The consent surface is honest about this: at install time the Store lists the app’s network declaration, and an app’s gateway-mediated reach is separately bounded by its api permission. What is not enforced is an app’s own outbound traffic from its own process.

What this means for you: treat an installed app’s network: true as a stated intent you are consenting to, the same way you would trust any program you choose to run — not as a sandbox that prevents the app from talking to the network. The supply-chain scanner (quarantine → scan → consent → install, with dangerous terminal) is the control that vets what you install; the network flag is disclosure, not containment.

Per the project’s lifecycle discipline, a control gap discovered while writing documentation is recorded as a candidate for the security-hardening track — never patched inline in a docs change. Both items above have a named future direction (OS-level app isolation for #2; extending the hard rail to ACP protocol paths for #1). This page will shrink as those land.