Security Layers
The TinyElf Agent engine implements a three-layer security pipeline to ensure tool calls undergo sufficient security verification before execution. The three layers execute in sequence, and rejection by any layer terminates the process.
Three-Layer Security Pipeline
graph TB
TC["Tool call request<br/>(toolName, args)"] --> L1
subgraph Layer1["Layer 1: ExecutionFirewall"]
L1["checkToolCall(name, args)"] --> L1a{"Path in deny list?"}
L1a -->|Yes| Block1["Block<br/>[firewall] Blocked"]
L1a -->|No| L1b{"Bash command contains deny path?"}
L1b -->|Yes| Block1
L1b -->|No| Pass1["Pass"]
end
Pass1 --> L2
subgraph Layer2["Layer 2: GuardianAgent"]
L2["review(name, args)"] --> L2a{"Mode = off?"}
L2a -->|Yes| Pass2a["Skip"]
L2a -->|No| L2b{"In review scope?"}
L2b -->|No| Pass2b["Skip"]
L2b -->|Yes| L2c["LLM risk assessment<br/>(15s timeout)"]
L2c --> L2d{"Risk level decision"}
L2d -->|"guard: high/critical"| Block2["Block<br/>[guardian] Blocked"]
L2d -->|"strict: medium+"| Block2
L2d -->|Allow| Pass2["Pass"]
end
Pass2 --> L3
Pass2a --> L3
Pass2b --> L3
subgraph Layer3["Layer 3: PermissionCallback"]
L3["isSensitiveTool(name)"] --> L3a{"Requires confirmation?"}
L3a -->|No| Pass3a["Auto-pass"]
L3a -->|Yes| L3b["Send confirmation request<br/>(5min timeout)"]
L3b --> L3c{"User reply"}
L3c -->|Allow| Pass3["Pass"]
L3c -->|AllowSession| Pass3s["Pass + cache"]
L3c -->|Deny/Timeout| Block3["Deny"]
end
Pass3 --> Exec["Execute tool"]
Pass3a --> Exec
Pass3s --> Exec
Layer 1: ExecutionFirewall
ExecutionFirewall is a deterministic security gateway that blocks access to sensitive system resources based on path pattern rules.
Interface
class ExecutionFirewall {
constructor(workspacePath: string);
checkPath(filePath: string, operation?: 'read' | 'write'): FirewallCheckResult;
checkCommand(command: string): FirewallCheckResult;
checkToolCall(toolName: string, params: Record<string, unknown>): FirewallCheckResult;
setWorkspacePath(newPath: string): void;
}
interface FirewallCheckResult {
allowed: boolean;
deniedBy?: string;
reason?: string;
}
Denied Path Rules
Both Read and Write Denied
| Path Pattern | Reason |
|---|---|
C:\Windows\ | Windows system directory |
C:\Program Files\ | Program installation directory |
C:\ProgramData\ | Program data directory |
C:\Recovery\ | Recovery partition |
/etc/ | System configuration directory |
/usr/ | System directory |
/sbin/ | System binaries |
/boot/ | Boot directory |
/proc/ | Process pseudo-filesystem |
/sys/ | System pseudo-filesystem |
/dev/ | Device files |
.ssh/ | SSH keys directory |
.gnupg/ | GPG keys directory |
.aws/ | AWS credentials |
.azure/ | Azure credentials |
.gcloud/ | GCloud credentials |
.kube/config | Kubernetes configuration |
.docker/config.json | Docker configuration |
id_rsa, id_ed25519, id_ecdsa | SSH private key files |
.env, .env.* | Environment variable files |
credentials.json | Credentials file |
service_account*.json | Service account keys |
| Firefox/Chrome/Edge user data | Browser configuration files |
System32\config\SAM/SYSTEM/... | Windows registry |
Write Denied Only (Readable)
| Path Pattern | Reason |
|---|---|
.gitconfig | Git configuration |
.npmrc | npm configuration |
.bashrc | Bash configuration |
.zshrc | Zsh configuration |
.profile | Shell configuration |
.bash_profile | Bash configuration |
Tool Path Parameter Mapping
| Tool | Extracted path parameter | Operation type |
|---|---|---|
Read | path, file_path | read |
Write | path, file_path | write |
Edit | path, file_path | write |
ListDir | path, dir_path | read |
Command Path Extraction
checkCommand() extracts paths from shell commands and checks each one:
- Windows absolute paths:
C:\path\to\file - POSIX absolute paths:
/path/to/file
Layer 2: GuardianAgent
GuardianAgent uses LLM to perform security risk assessment of tool calls.
Interface
class GuardianAgent {
constructor(
config: GuardianAgentConfig,
llmAdapter: TinyElfLLMAdapter,
auditLogger?: AuditLogger,
sessionId?: string,
workspacePath?: string,
);
review(toolName: string, args: Record<string, unknown>): Promise<GuardianReviewResult>;
clearCache(): void;
}
interface GuardianReviewResult {
allowed: boolean;
riskLevel: RiskLevel; // 'none' | 'low' | 'medium' | 'high' | 'critical'
reason: string;
cached: boolean;
}
Work Modes
| Mode | Review scope | Block condition | Timeout/error behavior |
|---|---|---|---|
off | None | No blocking | N/A |
monitor | Sensitive tools | No blocking (logging only) | N/A |
guard | Sensitive tools | high, critical | Fail open (allow) |
strict | All tools | medium, high, critical | Fail closed (deny) |
Sensitive Tools List
const SENSITIVE_TOOLS = new Set(['Bash', 'Write', 'Edit', 'Agent']);
monitor and guard modes review only these tools. strict mode reviews all tools.
Risk Levels
| Level | Meaning | Example |
|---|---|---|
none | Completely safe | Reading files within workspace |
low | Low risk | Writing project files |
medium | Medium risk | Installing packages, modifying state |
high | High risk | Operations outside workspace, network requests, credential access |
critical | Critical risk | Recursive deletion, privilege escalation, data theft |
Key Rules (always marked as high/critical)
- File deletion outside workspace
- Recursive delete commands (
rm -rf,del /s /q,Remove-Item -Recurse) - System directory operations (
/etc,C:\Windows) - User personal directory operations (Desktop, Documents)
- Privilege escalation (
sudo,runas) - Piped execution (
curl | sh) - Security bypass (
--no-verify,--force) - Credential access
Caching Strategy
- Approval results cached (key by first 16 bits of
sha256(toolName:args)) - Only allow results cached (deny results re-evaluated each time)
- Cache cleared at session end
Constants
| Constant | Value | Description |
|---|---|---|
GUARDIAN_TIMEOUT_MS | 15,000 | LLM assessment timeout |
Layer 3: PermissionCallback
TinyElfPermissionManager
class TinyElfPermissionManager {
resolvePermission(requestId: string, result: PermissionResult): void;
cleanupSession(dbSessionId: string): void;
requestPermission(dbSessionId, sender, toolName, toolInput): Promise<PermissionResult>;
buildPermissionCallback(dbSessionId, sender, permissionMode, channelCtx, channelPermissionGate):
((toolName, toolInput) => Promise<PermissionResult>) | undefined;
}
interface PermissionResult {
behavior: 'allow' | 'deny' | 'allowSession';
message?: string;
}
Permission Mode Behavior
| Mode | buildPermissionCallback returns |
|---|---|
bypassPermissions | undefined (no callback injected, all tools auto-pass) |
default | Desktop callback / Channel callback |
acceptEdits | Same as default, but Write/Edit return false in isSensitiveTool |
Session-Level Whitelist
When user selects allowSession:
sessionAllowedTools: Map<string, Set<string>> // dbSessionId → Set<toolName>
Subsequent calls with same tool name auto-pass. Whitelist cleared in cleanupSession().
Timeout
- Desktop mode: 5-minute timeout → auto deny
- Channel mode: 5-minute timeout → auto deny
ChannelPermissionGate
Permission confirmation in Channel scenarios is implemented via message routing.
Confirmation Flow
sequenceDiagram
participant A as TinyElfAgentLoop
participant G as ChannelPermissionGate
participant C as Channel (Discord/Telegram)
participant U as Channel User
A->>G: requestConfirmation(channelId, chatId, senderId, toolName, desc)
G->>G: Check always-allow list
alt Already in always-allow
G-->>A: true
else Not in list
G->>C: sendMessage("Confirmation needed: Bash: npm test")
C->>U: Display confirmation message
U->>C: Reply "y" / "n" / "always"
C->>G: processReply(channelId, chatId, senderId, "y")
G-->>A: true / false
end
Fingerprint Scope
The scope of always reply is determined by buildToolFingerprint():
fingerprint = `${toolName}:${description.slice(0, 120)}`
For example, Bash:npm test and Bash:rm -rf / are different fingerprints, requiring separate authorization.
Constants
| Constant | Value | Description |
|---|---|---|
MAX_PENDING | 5 | Max pending confirmations per Channel |
TIMEOUT_MS | 300,000 | Confirmation timeout (5 minutes) |
Reply Parsing
Supported confirmation replies (case-insensitive, auto-strips Discord mentions etc.):
| Reply | Behavior |
|---|---|
| y, yes, approve, ok, 确认, はい | Allow |
| n, no, deny, cancel, 拒绝, いいえ | Deny |
| always, always allow, 始终允许, 常に許可 | Allow + add to always list |
AuditLogger
All security events are logged to the audit_log database table.
Event Types
type AuditEventType =
| 'firewall_block'
| 'permission_denied'
| 'permission_granted'
| 'permission_timeout'
| 'rate_limited'
| 'role_changed'
| 'user_created'
| 'user_deleted'
| 'injection_detected'
| 'command_blocked'
| 'guardian_review'
| 'prompt_review';
type AuditSeverity = 'info' | 'warn' | 'critical';
Write Strategy
- Fire-and-forget: async write, does not block main flow
- Write failures silently handled (
console.warn), does not affect tool execution
Key Files
| File | Path | Description |
|---|---|---|
| ExecutionFirewall | platform/security/ExecutionFirewall.ts | Path firewall |
| GuardianAgent | platform/security/GuardianAgent.ts | AI security assessment |
| AuditLogger | platform/security/AuditLogger.ts | Audit logging |
| ChannelPermissionGate | platform/security/ChannelPermissionGate.ts | Channel permission gate |
| InputSanitizer | platform/security/InputSanitizer.ts | Input sanitization |
| PromptGuardian | platform/security/PromptGuardian.ts | Prompt injection detection |
| RateLimiter | platform/security/RateLimiter.ts | Rate limiting |
| UserPermissionService | platform/security/UserPermissionService.ts | User role permissions |
| TinyElfPermissions | agent-core/engine/tinyelf/TinyElfPermissions.ts | Permission manager |
All paths relative to packages/desktop/app/main/services/.
Extension Points
- Custom denied paths: add rules to
SYSTEM_DENIED_PATHSarray - Custom Guardian system prompt: modify
SYSTEM_PROMPTconstant - Custom audit events: add new types to
AuditEventType - Custom Channel replies: extend regex matching in
processReply
Related Modules
| Module | Path | Relationship |
|---|---|---|
| TinyElfAgentLoop | agent-core/engine/tinyelf/TinyElfAgentLoop.ts | Security pipeline caller |
| TinyElfSessionRunner | agent-core/engine/tinyelf/TinyElfSessionRunner.ts | Firewall/Guardian instantiation |
| ShellTool | agent-core/engine/tinyelf/tools/ShellTool.ts | Built-in command blacklist |
| TinyElfLLMAdapter | agent-core/engine/tinyelf/TinyElfLLMAdapter.ts | LLM used by Guardian |