This document describes the security features implemented in squid to protect users during LLM interactions with tool calling capabilities, including path validation and ignore patterns.
Quick Start: See the "Tool Calling (with Security Approval)" section in the main README.md for examples.
When the LLM requests to use tools (such as reading, writing, or searching files), squid provides multiple layers of security:
- Path Validation - Whitelist/blacklist rules prevent access to sensitive system directories
- Ignore Patterns -
.squidignorefile blocks access to specific files and directories - User Approval - Explicit confirmation required before executing any operation
This multi-layered approach prevents unauthorized or unintended file system access.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 1. User sends a query to the LLM β
β Example: "Read README.md and summarize it" β
βββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 2. LLM determines it needs to use a tool β
β Tool: read_file β
β Arguments: {"path": "README.md"} β
βββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 3. squid validates path (whitelist/blacklist + .squidignore)β
β β If blocked: Friendly message returned to LLM β
β (NO user prompt, LLM relays message) β
β β If allowed: Continue to step 4 β
βββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 4. squid prompts user for approval β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Allow reading file: README.md? (Y/n) β β
β β [Y] Allow [N] Skip β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 5. User makes decision β
β β’ Press Y β Tool executes, result sent to LLM β
β β’ Press N β Tool skipped, error sent to LLM β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Note: The LLM will still make tool call requests for protected files because it doesn't know which files are blocked beforehand. However, these requests are rejected instantly without user interaction, and the LLM receives a friendly message to relay to the user.
All file system operations are validated against whitelist and blacklist rules before requesting user approval.
Default Whitelist:
- Current directory (
.) and subdirectories - Current working directory path
Default Blacklist (System Paths):
/etc,/bin,/sbin,/usr/bin,/usr/sbin/root,/var,/sys,/procC:\Windows,C:\Program Files(Windows)
Default Blacklist (Sensitive User Files):
~/.ssh/- SSH keys~/.gnupg/- GPG keys~/.aws/- AWS credentials~/.config/gcloud/- Google Cloud credentials
Behavior:
- Paths outside the whitelist are automatically rejected
- Paths in the blacklist are automatically rejected
- User is never prompted for rejected paths
- Clear error messages explain why access was denied
Example:
squid ask "Read /etc/passwd"
# What happens:
# 1. LLM requests to read /etc/passwd
# 2. Path validation blocks it (blacklisted)
# 3. Friendly message returned to LLM (no user prompt)
# 4. LLM relays the message:
#
# π¦: I cannot access '/etc/passwd' because it's a protected system file
# or directory. Access to this location is blocked for security reasons.Use a .squidignore file in your project root to specify files and directories that should never be accessed by squid tools. This works like .gitignore.
Creating .squidignore:
# .squidignore - One pattern per line
# Lines starting with # are comments
# Build outputs
target/
dist/
*.o
# Dependencies
node_modules/
__pycache__/
# Secrets
.env
*.key
*.pem
# Logs
*.log
logs/
# OS files
.DS_StorePattern Syntax:
*.txt- All .txt files in any directory**/*.log- All .log files recursivelytarget/- Entire target directorynode_modules/**- node_modules and all contents# comment- Comments start with #
Priority:
Ignore patterns are checked after whitelist/blacklist but before user approval:
1. Path validation (whitelist/blacklist) β Automatic
2. Ignore patterns (.squidignore) β Automatic
3. User approval prompt β Manual
Example:
# Create .squidignore
echo "*.log" > .squidignore
echo ".env" >> .squidignore
squid ask "Read debug.log"
# What happens:
# 1. LLM requests to read debug.log
# 2. Path validation blocks it (.squidignore pattern match)
# 3. Friendly message returned to LLM (no user prompt)
# 4. LLM relays the message:
#
# π¦: I cannot access 'debug.log' because it's protected by the project's
# .squidignore file. This is a security measure to prevent access to
# sensitive files.All tool executions require explicit user approval. The LLM cannot read, write, or search files without user consent.
squid ask "Read my secret.txt file"
# Prompt: Allow reading file: secret.txt? (Y/n)
# β You control whether this happens
squid ask "Search for passwords in the project"
# Prompt: Allow searching for pattern 'passwords' in: .? (Y/n)
# β You control whether this happensSquid uses agent-based permissions where each agent defines which tools can run automatically (without confirmation) or should never run at all.
Configuration:
{
"agents": {
"general-assistant": {
"name": "General Assistant",
"enabled": true,
"description": "Full-featured coding assistant",
"model": "qwen2.5-coder",
"permissions": {
"allow": ["now", "read_file", "write_file", "grep", "bash:ls", "bash:git"],
"deny": []
}
},
"code-reviewer": {
"name": "Code Reviewer",
"enabled": true,
"description": "Reviews code (read-only)",
"model": "qwen2.5-coder",
"permissions": {
"allow": ["now", "read_file", "grep"],
"deny": ["write_file", "bash"]
}
}
},
"default_agent": "general-assistant"
}Fields:
allow- Tools that run automatically without user confirmationdeny- Tools that are completely blocked and will never run
Default Behavior:
- Each agent defines its own permission set
- CLI commands use the
default_agentpermissions - Web UI uses the selected agent's permissions
- All other tools require confirmation on first use
Interactive Permission Management:
When prompted for tool approval, you have four options:
Can I read this file?
π File: config.json
β― Yes (this time)
No (skip)
Always (add to allow list)
Never (add to deny list)Options:
- Yes (this time) - Allow once, ask again next time
- No (skip) - Deny once, ask again next time
- Always (add to allow list) - Allow this tool permanently for the current agent, auto-save to config
- Never (add to deny list) - Block this tool permanently for the current agent, auto-save to config
Permission Priority:
- Deny list (highest priority) - Tool is blocked immediately
- Allow list - Tool runs without confirmation
- Default - User is prompted for approval
Security Notes:
- Permissions are stored per-agent in
squid.config.json - Different agents can have different permission levels
- Path validation still applies to allowed tools (whitelist/blacklist/.squidignore)
- Denied tools return an error to the LLM without user interaction
Each agent's bash permissions support granular control for fine-grained management of which commands can run without approval:
Format:
"bash"- Allows all bash commands (uses internal safety checks)"bash:ls"- Allows onlylscommands (ls,ls -la,ls -l, etc.)"bash:git"- Allows onlygitcommands (any git subcommand)"bash:git status"- Allows onlygit statuscommands specifically"bash:cat"- Allows onlycatcommands
Example Agent Configuration with Granular Bash Permissions:
{
"agents": {
"safe-explorer": {
"name": "Safe Explorer",
"enabled": true,
"description": "Read-only agent with safe bash commands",
"model": "qwen2.5-coder",
"permissions": {
"allow": [
"now",
"read_file",
"grep",
"bash:ls",
"bash:git status",
"bash:pwd"
],
"deny": [
"write_file",
"bash:rm",
"bash:sudo"
]
}
}
}
}This agent configuration:
- β
Auto-approves
lscommands without prompting - β
Auto-approves
git status(but not other git commands) - β
Auto-approves
pwdcommand - β Blocks all
rmcommands (in addition to built-in blocking) - β Blocks all
sudocommands (in addition to built-in blocking) - β Prompts for other bash commands (like
cat,echo,git log)
How Granular Permissions Work:
When you choose Always or Never for a bash command, the system automatically extracts the base command and saves it:
# User approves: "ls -la" with "Always"
# Saved as: "bash:ls"
# Now allows: ls, ls -la, ls -l, etc.
# User approves: "git status" with "Always"
# Saved as: "bash:git status"
# Now allows: git status, git status --short
# Still prompts for: git log, git commit, etc.
# User denies: "rm -rf temp" with "Never"
# Saved as: "bash:rm"
# Now blocks: rm, rm -rf, rm -f, etc.Benefits:
- π― Precision: Allow only specific safe commands
- π Safety: Deny dangerous commands beyond built-in blocks
- β‘ Efficiency: Reduce prompts for frequently used safe commands
- π Clarity: Config clearly shows which commands are trusted
Critical Security Note:
Dangerous command patterns (rm, sudo, chmod, dd, curl, wget, kill) are always blocked at the code level and cannot be bypassed by:
- Adding
"bash"to allow list - Adding
"bash:rm"to allow list - User approval
- Any configuration setting
These blocks are hardcoded for your safety and cannot be overridden.
When the LLM attempts to write a file, you see a preview of the content before approving:
squid ask "Create a config.json file with default settings"
# You'll see:
# Allow writing to file: config.json?
# Content preview:
# {
# "version": "1.0",
# "debug": false,
# "port": 8080
# }
# (Y/n)For large content (>100 bytes), only the first 100 bytes are shown with a total size indicator.
When the LLM attempts to search files using grep, you see the exact pattern and path:
squid ask "Find all TODO comments in src"
# You'll see:
# Allow searching for pattern 'TODO' in: src? (Y/n)Search features:
- Regex pattern matching with case sensitivity options
- Recursive directory search or single file search
- Results show file path, line number, and matched content
- Automatic binary file filtering for safety
- Configurable result limits (default: 50 matches)
All tool calls are logged for transparency and audit purposes:
[INFO] Tool call: read_file with args: {"path":"README.md"}
[INFO] Successfully read file: README.md (2847 bytes)
Or if denied:
[INFO] Tool call: write_file with args: {"path":"secret.txt","content":"..."}
[INFO] Tool execution skipped by user: write_file
Users can deny any tool execution at any time:
- Press
Nto skip the operation - The LLM receives an error message
- The LLM can adapt its response based on the denial
- No files are accessed or modified
Purpose: Read contents from the file system
Security measures:
- Shows exact file path before approval
- No preview of file contents (you approve based on the path)
- Logged with file size after successful read
Example prompt:
Allow reading file: /path/to/file.txt? (Y/n)
Purpose: Write content to the file system
Security measures:
- Shows exact file path before approval
- Displays content preview (first 100 bytes)
- Shows total byte count for large files
- Logged with file size after successful write
Example prompt:
Allow writing to file: output.txt?
Content preview:
Hello, World!
This is a test file.
(Y/n)
Purpose: Get current date and time in RFC 3339 format
Security measures:
- Shows which timezone will be used (UTC or local)
- No sensitive data access - only system time
- Logged with timezone information
Example prompt:
Allow getting current date and time?
Timezone: utc
(Y/n)
Purpose: Execute safe, non-destructive bash commands for system inspection
Security measures:
- MANDATORY blocking of dangerous commands - Cannot be bypassed by configuration or user approval
- Blocked patterns (hardcoded):
rm -rf,rm -f,sudo,chmod,dd,mkfs,fdisk,curl,wget,kill,pkill,killall - Dangerous commands are blocked before permission checks and user prompts
- Shows exact command and timeout before approval (for non-dangerous commands)
- Configurable timeout (default: 10 seconds, max: 60 seconds)
- Command execution wrapped in timeout protection
- Logged with command and execution status
Allowed use cases:
- Information gathering:
ls,ls -la,pwd - Git inspection:
git status,git log,git branch - File viewing:
cat file.txt,head,tail - System info:
echo,date,uname - Search operations:
find, command-linegrep
Example prompt:
Allow executing bash command?
Command: ls -la
Timeout: 10 seconds
(Y/n)
Security notes:
- Commands are executed in a shell subprocess with timeout protection
- Dangerous commands are blocked before user approval is requested
- Even if a command is in the allow list, dangerous patterns are still blocked
- Path validation does not apply (bash operates on the shell level)
- Users should review commands carefully before approval
Example of blocked command:
squid ask "Delete all temporary files with rm -rf /tmp/*"
# What happens:
# 1. LLM requests to execute: rm -rf /tmp/*
# 2. MANDATORY security check detects "rm -rf" pattern (happens BEFORE permissions)
# 3. Command is blocked immediately (no permission check, no user prompt)
# 4. Error returned to LLM:
#
# π¦: Command blocked for security reasons. The command contains a
# dangerous pattern: 'rm -rf'. Commands like rm, sudo, chmod, dd, curl,
# wget, and kill operations are not allowed.Even with "bash" in agent allow list:
{
"agents": {
"general-assistant": {
"permissions": {
"allow": ["bash"] // Allow all bash? NO - dangerous commands still blocked!
}
}
}
}squid ask "Run: rm -rf temp"
# Still blocked! Dangerous patterns cannot be bypassed by configuration.In addition to LLM tool calls, squid provides direct file access via command-line flags:
ask -f <file>- Passes file content directly to the LLM with your questionreview <file>- Reads file for code review
Security measures:
- Path validation applied BEFORE reading - Same whitelist/blacklist and
.squidignorechecks as tool calls - No user approval prompt - Validation happens immediately when command runs
- Friendly error messages - Clear explanation if file is blocked
- Cannot bypass security - No way to override validation rules
Example blocked access:
$ squid ask -f .env "what's in this file?"
π¦: I can't access that file - it's in your .squidignore list.
$ squid review ~/.ssh/id_rsa
π¦: I can't access that file - it's outside the project directory or in a protected system location.Example allowed access:
$ squid ask -f src/main.rs "explain this code"
# File is validated, then read and passed to LLM
# No approval prompt needed - you explicitly requested it via -f flagWhy direct file access is safe:
- You explicitly specify the file path in the command
- Same security validation as tool calls (blacklist, whitelist, .squidignore)
- Path validation happens before file is read
- Clear error messages if access is denied
Key difference from tool calls:
- Tool calls: LLM decides what to read β validation β user approval β read
- Direct access: You decide what to read β validation β read (no approval needed since you chose the file)
- Review file paths carefully before approving read operations
- Check content previews for write operations
- Deny suspicious requests - You can always run the command again
- Use absolute paths when possible to avoid ambiguity
- Enable debug logging if you want more detailed information:
RUST_LOG=debug squid ask "your question"
- Blindly approve all tool executions
- Allow reads of sensitive files (
.env, private keys, passwords) - Approve writes without checking the content preview
- Ignore unexpected tool requests - If you didn't expect file access, press N
Command:
squid ask "What environment variables do I have?"LLM may try:
Tool: read_file
Path: .env
What happens:
- LLM requests to read
.env(doesn't know it's blocked) - Path validation checks
.envagainst.squidignore .envis blocked automatically (in default.squidignore)- You are NOT prompted - access denied immediately
- LLM receives friendly message: "I cannot access '.env' because it's protected by the project's .squidignore file. This is a security measure to prevent access to sensitive files."
- LLM relays the message to the user
- Your sensitive data stays protected without user interaction needed
Note: The LLM will still consume tokens for the initial request and the follow-up response, but no sensitive data is ever accessed.
Command:
squid ask "Create a startup script for this project"LLM may try:
Tool: write_file
Path: startup.sh
Content: #!/bin/bash
rm -rf / # Malicious content
Your response:
- Review the content preview
- See the malicious
rm -rf /command - Press
Nto deny - File is not created
Command:
squid ask "Read all .rs files in src/ and create a summary"LLM behavior:
- Requests to read each file individually
- Path validation passes for project files
- You approve each one: src/main.rs β, src/lib.rs β, etc.
- If LLM tries to read ignored files (e.g.,
target/), they're blocked automatically - Finally requests to write summary.txt
- Path validation passes, you review the summary content
- Approve if it looks correct
All tool operations are logged at the INFO level. To view these logs:
# Default (shows INFO and above)
RUST_LOG=info squid ask "your question"
# Debug (shows all logs including tool details)
RUST_LOG=debug squid ask "your question"
# Only errors
RUST_LOG=error squid ask "your question"Log examples:
[INFO] Tool call: read_file with args: {"path":"README.md"}
[INFO] Successfully read file: README.md (2847 bytes)
[INFO] Tool call: write_file with args: {"path":"summary.txt","content":"..."}
[INFO] Successfully wrote file: summary.txt (156 bytes)
Or when denied:
[INFO] Tool call: read_file with args: {"path":".env"}
[INFO] Tool execution skipped by user: read_file
The security approval is implemented using the inquire library, which provides:
- Cross-platform terminal prompts
- Default to
false(deny by default) - Clear yes/no options
- Keyboard-only operation (Y/N keys)
If squid is run in a non-interactive environment (e.g., piped input, CI/CD), tool approval will fail with an error:
[ERROR] Failed to get user approval: not a terminal
This is intentional - tools require human approval and cannot run unattended.
Squid employs three layers of security for file operations:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 1: Path Validation (Whitelist/Blacklist) β
β β Blocks system directories (/etc, /root, etc.) β
β β Blocks sensitive files (~/.ssh, ~/.aws, etc.) β
β β Only allows current directory and subdirectories β
β β Automatic rejection, no user prompt β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 2: Ignore Patterns (.squidignore) β
β β Blocks files matching .squidignore patterns β
β β Configurable per-project rules β
β β Works like .gitignore β
β β Automatic rejection, no user prompt β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 3: User Approval β
β β Explicit Y/N prompt for each operation β
β β Content preview for write operations β
β β Full transparency of tool arguments β
β β Manual approval required β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Example Flow:
squid ask "Read all files in my project and create a summary"
# Attempt 1: Read ~/.ssh/id_rsa
# β Layer 1 blocks (blacklisted path)
# β Automatic rejection
# Attempt 2: Read node_modules/package/index.js
# β Layer 2 blocks (in .squidignore)
# β Automatic rejection
# Attempt 3: Read src/main.rs
# β Layers 1&2 pass
# β Layer 3 prompts user
# ? Allow reading file: src/main.rs? (Y/n)Potential future security features (not yet implemented):
- Automatic approval for specific safe operations
- Audit log file for all tool executions
- Configuration option to disable tools entirely
- Sandboxing or restricted file system access
- Rate limiting for tool calls
- Custom whitelist paths via configuration
If you discover a security vulnerability in squid, please report it responsibly:
- DO NOT create a public GitHub issue
- Contact the maintainer directly (see
Cargo.tomlfor author email) - Provide detailed information about the vulnerability
- Allow time for a fix before public disclosure
The security system in squid provides:
β
Path Validation - Automatic blocking of system and sensitive directories
β
Ignore Patterns - Project-specific file blocking via .squidignore
β
User Control - Final approval for every file operation
β
Transparency - See what's being accessed and written
β
Logging - Complete audit trail of all operations
β
Prevention - Multi-layered defense against unintended or malicious actions
Your security is our priority. Use squid with confidence knowing you're protected at multiple levels.