安全层
TinyElf Agent 引擎实现了三层安全管道,确保工具调用在执行前经过充分的安全验证。三层按顺序执行,任一层拒绝即终止。
三层安全管道
graph TB
TC["工具调用请求<br/>(toolName, args)"] --> L1
subgraph Layer1["第一层: ExecutionFirewall"]
L1["checkToolCall(name, args)"] --> L1a{"路径在禁止列表中?"}
L1a -->|是| Block1["阻止<br/>[firewall] Blocked"]
L1a -->|否| L1b{"Bash 命令含禁止路径?"}
L1b -->|是| Block1
L1b -->|否| Pass1["通过"]
end
Pass1 --> L2
subgraph Layer2["第二层: GuardianAgent"]
L2["review(name, args)"] --> L2a{"模式 = off?"}
L2a -->|是| Pass2a["跳过"]
L2a -->|否| L2b{"在审查范围内?"}
L2b -->|否| Pass2b["跳过"]
L2b -->|是| L2c["LLM 风险评估<br/>(15s 超时)"]
L2c --> L2d{"风险等级判定"}
L2d -->|"guard: high/critical"| Block2["阻止<br/>[guardian] Blocked"]
L2d -->|"strict: medium+"| Block2
L2d -->|允许| Pass2["通过"]
end
Pass2 --> L3
Pass2a --> L3
Pass2b --> L3
subgraph Layer3["第三层: PermissionCallback"]
L3["isSensitiveTool(name)"] --> L3a{"需要确认?"}
L3a -->|否| Pass3a["自动通过"]
L3a -->|是| L3b["发送确认请求<br/>(5min 超时)"]
L3b --> L3c{"用户回复"}
L3c -->|Allow| Pass3["通过"]
L3c -->|AllowSession| Pass3s["通过 + 缓存"]
L3c -->|Deny/Timeout| Block3["拒绝"]
end
Pass3 --> Exec["执行工具"]
Pass3a --> Exec
Pass3s --> Exec
第一层:ExecutionFirewall
ExecutionFirewall 是确定性的安全网关,基于路径模式规则阻止对敏感系统资源的访问。
接口
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;
}
禁止路径规则
读写均禁止
| 路径模式 | 原因 |
|---|---|
C:\Windows\ | Windows 系统目录 |
C:\Program Files\ | 程序安装目录 |
C:\ProgramData\ | 程序数据目录 |
C:\Recovery\ | 恢复分区 |
/etc/ | 系统配置目录 |
/usr/ | 系统目录 |
/sbin/ | 系统二进制文件 |
/boot/ | 引导目录 |
/proc/ | 进程伪文件系统 |
/sys/ | 系统伪文件系统 |
/dev/ | 设备文件 |
.ssh/ | SSH 密钥目录 |
.gnupg/ | GPG 密钥目录 |
.aws/ | AWS 凭据 |
.azure/ | Azure 凭据 |
.gcloud/ | GCloud 凭据 |
.kube/config | Kubernetes 配置 |
.docker/config.json | Docker 配置 |
id_rsa, id_ed25519, id_ecdsa | SSH 私钥文件 |
.env, .env.* | 环境变量文件 |
credentials.json | 凭据文件 |
service_account*.json | 服务账户密钥 |
| Firefox/Chrome/Edge 用户数据 | 浏览器配置文件 |
System32\config\SAM/SYSTEM/... | Windows 注册表 |
仅写入禁止(可读)
| 路径模式 | 原因 |
|---|---|
.gitconfig | Git 配置 |
.npmrc | npm 配置 |
.bashrc | Bash 配置 |
.zshrc | Zsh 配置 |
.profile | Shell 配置 |
.bash_profile | Bash 配置 |
工具路径参数映射
| 工具名 | 提取的路径参数 | 操作类型 |
|---|---|---|
Read | path, file_path | read |
Write | path, file_path | write |
Edit | path, file_path | write |
ListDir | path, dir_path | read |
命令路径提取
checkCommand() 从 Shell 命令中提取路径并逐一检查:
- Windows 绝对路径:
C:\path\to\file - POSIX 绝对路径:
/path/to/file
第二层:GuardianAgent
GuardianAgent 使用 LLM 对工具调用进行安全风险评估。
接口
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;
}
工作模式
| 模式 | 审查范围 | 阻止条件 | 超时/错误行为 |
|---|---|---|---|
off | 无 | 不阻止 | N/A |
monitor | 敏感工具 | 不阻止(仅记录) | N/A |
guard | 敏感工具 | high, critical | 失败开放(允许) |
strict | 所有工具 | medium, high, critical | 失败关闭(拒绝) |
敏感工具列表
const SENSITIVE_TOOLS = new Set(['Bash', 'Write', 'Edit', 'Agent']);
monitor 和 guard 模式仅审查这些工具。strict 模式审查所有工具。
风险等级
| 等级 | 含义 | 示例 |
|---|---|---|
none | 完全安全 | 读取工作区内文件 |
low | 低风险 | 写入项目文件 |
medium | 中等风险 | 安装包、修改状态 |
high | 高风险 | 工作区外操作、网络请求、凭据访问 |
critical | 关键风险 | 递归删除、权限提升、数据窃取 |
关键规则(始终标记为 high/critical)
- 工作区外的文件删除
- 递归删除命令(
rm -rf、del /s /q、Remove-Item -Recurse) - 系统目录操作(
/etc、C:\Windows) - 用户个人目录操作(Desktop、Documents)
- 权限提升(
sudo、runas) - 管道执行(
curl | sh) - 安全绕过(
--no-verify、--force) - 凭据访问
缓存策略
- 审批结果缓存(按
sha256(toolName:args)的前 16 位做 key) - 仅缓存允许的结果(拒绝结果每次重新评估)
- 会话结束时清除缓存
常量
| 常量 | 值 | 说明 |
|---|---|---|
GUARDIAN_TIMEOUT_MS | 15,000 | LLM 评估超时 |
第三层: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;
}
权限模式行为
| 模式 | buildPermissionCallback 返回 |
|---|---|
bypassPermissions | undefined(不注入回调,所有工具自动通过) |
default | 桌面回调 / Channel 回调 |
acceptEdits | 同 default,但 Write/Edit 在 isSensitiveTool 中返回 false |
会话级白名单
当用户选择 allowSession 时:
sessionAllowedTools: Map<string, Set<string>> // dbSessionId → Set<toolName>
后续同一工具名的调用自动通过。白名单在 cleanupSession() 中清除。
超时
- 桌面模式:5 分钟超时 → 自动 deny
- Channel 模式:5 分钟超时 → 自动 deny
ChannelPermissionGate
Channel 场景下的权限确认通过消息路由实现。
确认流程
sequenceDiagram
participant A as TinyElfAgentLoop
participant G as ChannelPermissionGate
participant C as Channel (Discord/Telegram)
participant U as Channel 用户
A->>G: requestConfirmation(channelId, chatId, senderId, toolName, desc)
G->>G: 检查 always-allow 列表
alt 已在 always-allow
G-->>A: true
else 未在列表中
G->>C: sendMessage("需要确认: Bash: npm test")
C->>U: 显示确认消息
U->>C: 回复 "y" / "n" / "always"
C->>G: processReply(channelId, chatId, senderId, "y")
G-->>A: true / false
end
指纹作用域
always 回复的作用域由 buildToolFingerprint() 决定:
fingerprint = `${toolName}:${description.slice(0, 120)}`
例如 Bash:npm test 和 Bash:rm -rf / 是不同的指纹,需要分别授权。
常量
| 常量 | 值 | 说明 |
|---|---|---|
MAX_PENDING | 5 | 每个 Channel 最大待确认数 |
TIMEOUT_MS | 300,000 | 确认超时(5 分钟) |
回复解析
支持的确认回复(大小写不敏感,自动去除 Discord 提及等格式):
| 回复 | 行为 |
|---|---|
| y, yes, approve, ok, 确认, はい | 允许 |
| n, no, deny, cancel, 拒绝, いいえ | 拒绝 |
| always, always allow, 始终允许, 常に許可 | 允许 + 加入 always 列表 |
AuditLogger
所有安全事件记录到 audit_log 数据库表。
事件类型
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';
写入策略
- Fire-and-forget:异步写入,不阻塞主流程
- 写入失败静默处理(
console.warn),不影响工具执行
关键文件
| 文件 | 路径 | 说明 |
|---|---|---|
| ExecutionFirewall | platform/security/ExecutionFirewall.ts | 路径防火墙 |
| GuardianAgent | platform/security/GuardianAgent.ts | AI 安全评估 |
| AuditLogger | platform/security/AuditLogger.ts | 审计日志 |
| ChannelPermissionGate | platform/security/ChannelPermissionGate.ts | Channel 权限门控 |
| InputSanitizer | platform/security/InputSanitizer.ts | 输入清理 |
| PromptGuardian | platform/security/PromptGuardian.ts | 提示注入检测 |
| RateLimiter | platform/security/RateLimiter.ts | 速率限制 |
| UserPermissionService | platform/security/UserPermissionService.ts | 用户角色权限 |
| TinyElfPermissions | agent-core/engine/tinyelf/TinyElfPermissions.ts | 权限管理器 |
所有路径相对于 packages/desktop/app/main/services/。
扩展点
- 自定义禁止路径:在
SYSTEM_DENIED_PATHS数组中添加规则 - 自定义 Guardian 系统提示:修改
SYSTEM_PROMPT常量 - 自定义审计事件:在
AuditEventType中添加新类型 - 自定义 Channel 回复:在
processReply中扩展正则匹配
相关模块
| 模块 | 路径 | 关系 |
|---|---|---|
| TinyElfAgentLoop | agent-core/engine/tinyelf/TinyElfAgentLoop.ts | 安全管道调用方 |
| TinyElfSessionRunner | agent-core/engine/tinyelf/TinyElfSessionRunner.ts | Firewall/Guardian 实例化 |
| ShellTool | agent-core/engine/tinyelf/tools/ShellTool.ts | 自带命令黑名单 |
| TinyElfLLMAdapter | agent-core/engine/tinyelf/TinyElfLLMAdapter.ts | Guardian 使用的 LLM |