OpenAI Codex 安全机制架构详解

近期 Openclaw 项目引发了 Agent 安全讨论——用户担心 AI 执行恶意命令、修改敏感文件、泄露密钥。Codex 作为先行者,其多层防护机制为同类项目提供了可借鉴的安全范式。理解 Codex 如何解决问题,有助于评估和改进其他 Agent 的安全设计。

广泛采用:作为 OpenAI 官方推出的 Coding Agent,Codex 是目前使用最广泛的 AI 编程工具之一。其安全架构经过大量用户验证,代表了业界较高水平。

开源透明:Codex 核心代码(codex-rs)在 GitHub 开源,可以深入分析其安全实现细节,而非依赖黑盒猜测。这为理解"生产级 AI Agent 如何做安全"提供了难得的学习样本。


1. 问题背景

AI 执行命令存在三类风险:

  1. 命令错误:AI 误判导致执行错误命令
  2. 命令注入:AI 被诱导执行恶意命令
  3. 程序替换:别名、PATH 劫持导致执行非预期程序

此外,AI 运行过程中还涉及敏感信息保护问题:API Key 可能泄露到日志、进程内存可能被窃取、用户密码可能被输出到终端。Codex 通过多层防护机制解决这些问题。


2. 整体架构

┌─────────────────────────────────────────────────────────────────┐
│   命令执行请求                                                  │
│         │                                                       │
│         ▼                                                       │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │  第一层:执行策略(决策层)                               │  │
│   │  • 命令安全检查:安全白名单 / 危险黑名单                  │  │
│   │  • 规则匹配:Allow / Prompt / Forbidden                  │  │
│   │  • Shell Tool MCP:拦截 execve(),获取真实程序路径       │  │
│   └─────────────────────────────────────────────────────────┘  │
│         │                                                       │
│         ▼                                                       │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │  第二层:进程加固(防护层)                               │  │
│   │  • 禁止调试器附加(ptrace)                              │  │
│   │  • 禁止动态库注入(LD_PRELOAD / DYLD_INSERT_LIBRARIES)  │  │
│   │  • 禁止 core dump                                        │  │
│   └─────────────────────────────────────────────────────────┘  │
│         │                                                       │
│         ▼                                                       │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │  第三层:沙箱隔离(限制层)                               │  │
│   │  • 文件系统:只读默认 + 白名单可写                        │  │
│   │  • 网络隔离:完全隔离 / 代理模式                          │  │
│   │  • 系统调用过滤:seccomp                                  │  │
│   └─────────────────────────────────────────────────────────┘  │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │  独立模块:Secrets 管理                                   │  │
│   │  • 敏感信息存储:OS Keyring + age 加密                    │  │
│   │  • 输出脱敏:自动隐藏 API Key / Token / 密码              │  │
│   └─────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘

3. 第一层:执行策略

当用户在 Shell 中输入 ls -la 时,Shell 最终会调用 execve() 系统函数:

int execve(const char *pathname, char *const argv[], char *const envp[]);

这个函数接收三个参数:要执行的程序路径(如 /bin/ls)、参数列表和环境变量。Codex 的第一层防护正是通过拦截这个调用,在程序真正执行前进行安全检查。

3.1 决策类型

决策 行为 使用场景
Allow 直接执行 已知安全的命令
Prompt 弹窗确认 需要用户批准的操作
Forbidden 拒绝执行 明确禁止的命令

优先级Forbidden > Prompt > Allow

3.2 命令安全检查

在规则匹配之前,Codex 首先进行命令安全检查,分为两个维度:

安全白名单is_known_safe_command):这些命令只读、无副作用,自动判定为安全:

cat, cd, cut, echo, expr, false, grep, head, id, ls, 
nl, paste, pwd, rev, seq, stat, tail, tr, true, uname, 
uniq, wc, which, whoami

部分命令需要检查参数:

命令 安全条件 危险参数示例
base64 无输出文件参数 -o, --output
find 无执行/删除操作 -exec, -delete, -fls
rg 无外部命令执行 --pre, --search-zip
git 只读子命令 push, reset --hard
sed 只读模式 -n {N}p 格式

对于 bash -lc "..." 形式的复合命令,Codex 会解析其中的每个子命令,只有全部安全才判定为安全。

危险黑名单command_might_be_dangerous):这些命令强制触发用户确认:

// rm -f / rm -rf 强制需要确认
Some("rm") => matches!(command.get(1), Some("-f" | "-rf")),

// sudo 检查子命令是否危险
Some("sudo") => is_dangerous_to_call_with_exec(&command[1..]),

// 危险的 git 子命令
Some("git") => matches!(subcommand, "push" | "reset" | "checkout" | "rebase"),

// 网络相关
Some("curl" | "wget") => true,  // 可能下载数据
Some("nc" | "ncat") => true,    // 网络通信

3.3 规则匹配流程

命令: npm install lodash
        │
        ▼
┌────────────────────────────────────────┐
│ 1. 命令安全检查                         │
│    • 安全白名单? → Allow               │
│    • 危险黑名单? → Prompt              │
└────────────────────────────────────────┘
        │ 不在名单
        ▼
┌────────────────────────────────────────┐
│ 2. 规则匹配                             │
│    • 用程序名作为索引查找规则           │
│    • 检查子命令/参数是否匹配            │
│    • 匹配成功 → 返回对应决策            │
└────────────────────────────────────────┘
        │ 未匹配
        ▼
┌────────────────────────────────────────┐
│ 3. 路径解析                             │
│    • 提取程序名(处理完整路径)         │
│    • 验证路径是否在允许列表             │
└────────────────────────────────────────┘
        │ 未匹配
        ▼
┌────────────────────────────────────────┐
│ 4. 默认回退                             │
│    根据用户配置决定:                   │
│    • suggest: 建议确认(默认)          │
│    • auto-edit: 自动批准编辑           │
│    • full-auto: 全自动执行             │
└────────────────────────────────────────┘

3.4 自定义规则

用户在 .codex/rules 文件中定义:

# 允许 npm install/run/test
rule(
    pattern = ["npm", ["install", "run", "test"]],
    decision = "allow",
)

# 禁止 sudo
rule(
    pattern = ["sudo"],
    decision = "forbidden",
)

# git push 需确认
rule(
    pattern = ["git", "push"],
    decision = "prompt",
)

3.5 Approval 确认流程

当决策为 Prompt 时,Codex 通过 TUI 界面向用户展示确认请求:

┌─────────────────────────────────────────────────────────────────┐
│  ⚠️  Approval Required                                          │
│                                                                 │
│  Command: rm -rf ./dist                                         │
│  Reason: Destructive operation detected                         │
│                                                                 │
│  [Y] Approve    [N] Deny    [E] Edit    [A] Approve All        │
└─────────────────────────────────────────────────────────────────┘

用户可以配置确认策略(approval_policy):

策略 行为
suggest 危险操作建议确认(默认)
on-failure 仅失败时确认
on-request 仅用户请求时确认
never 从不确认(危险)

3.6 Shell Tool MCP:execve 拦截机制

规则匹配依赖命令名,但实际执行的程序可能不同:

alias ls='rm -rf /'           # 别名替换
export PATH="~/bin:$PATH"     # PATH 中放置恶意程序
ln -s /bin/rm ~/bin/ls        # 符号链接

要解决这个问题,需要在 execve() 被调用时获取真实的程序路径。Codex 通过修改 Shell 实现这一点。

架构设计

Codex 使用 MCP(Model Context Protocol)协议实现 Shell 工具。MCP 是 Anthropic 提出的 AI 工具调用标准,定义了模型与外部工具之间的通信方式。主进程与 Shell 之间通过 Unix Domain Socket 通信——这是一种本地进程间通信机制,比 TCP socket 更高效,不经过网络栈,直接在内核中传递数据,且支持文件描述符传递。

┌─────────────────────────────────────────────────────────────────┐
│  Codex 主进程                                                   │
│       │                                                         │
│       │ 启动 Shell 时设置环境变量:                              │
│       │   EXEC_WRAPPER=/path/to/codex-execve-wrapper            │
│       │   CODEX_ESCALATE_SOCKET=<fd>                            │
│       ▼                                                         │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  打补丁的 Shell(bash-fork / zsh-fork)                  │   │
│  │                                                         │   │
│  │  正常 Shell:                                             │   │
│  │    execve("/bin/ls", ["ls", "-la"], env)                │   │
│  │                                                         │   │
│  │  打补丁后:                                               │   │
│  │    if (EXEC_WRAPPER 环境变量存在) {                      │   │
│  │        execve(EXEC_WRAPPER, ["/bin/ls", "ls", "-la"])   │   │
│  │    }                                                    │   │
│  └─────────────────────────────────────────────────────────┘   │
│       │                                                         │
│       ▼                                                         │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  codex-execve-wrapper                                    │   │
│  │                                                         │   │
│  │  1. 解析参数:file="/bin/ls", argv=["ls", "-la"]        │   │
│  │  2. 通过 Unix Socket 发送请求到主进程:                  │   │
│  │     EscalateRequest {                                   │   │
│  │         file: "/bin/ls",                                │   │
│  │         argv: ["ls", "-la"],                            │   │
│  │         workdir: "/home/user/project",                  │   │
│  │         env: {...}                                      │   │
│  │     }                                                   │   │
│  │  3. 等待主进程响应:                                     │   │
│  │     EscalateResponse { action: Run | Escalate | Deny }  │   │
│  │  4. 根据响应执行或拒绝                                   │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

通信协议

请求结构

struct EscalateRequest {
    file: PathBuf,        // 解析后的绝对路径
    argv: Vec<String>,    // 参数列表(含 argv[0])
    workdir: PathBuf,     // 工作目录
    env: HashMap<String, String>,
}

响应结构

enum EscalateAction {
    Run,                              // 允许执行
    Escalate,                         // 提升权限执行(脱离沙箱)
    Deny { reason: Option<String> },  // 拒绝执行
}

wrapper 收到的是解析后的绝对路径 /bin/ls,而非命令名 ls,因此可以准确判断实际执行的程序。


4. 第二层:进程加固

即使命令被允许执行,进程本身仍可能受到攻击。攻击者可能通过调试器读取进程内存中的敏感数据(如 API Key),或通过动态库注入劫持进程行为。

4.1 攻击向量

ptrace 攻击ptrace 是 Unix 系统调用,用于进程调试。调试器(如 gdb)通过它附加到目标进程,可以读取/写入进程内存、单步执行指令、捕获信号。攻击者同样可以利用 ptrace 读取进程中的敏感数据。

动态库注入

LD_PRELOAD=/tmp/malicious.so /usr/bin/some-program

core dump 泄露:进程崩溃时可能生成内存转储文件(core dump),其中可能包含敏感信息。

4.2 加固实现

Codex 在 main() 之前执行 pre_main_hardening() 函数(通过 #[ctor::ctor] 宏实现),确保进程启动时就处于安全状态。

Linux

// 1. 禁止 ptrace 附加
prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);

// 2. 禁止 core dump
setrlimit(RLIMIT_CORE, 0);

// 3. 清除动态库注入变量
unsetenv("LD_PRELOAD");
unsetenv("LD_LIBRARY_PATH");
// ... 清除所有 LD_* 变量

macOS

// 1. 禁止调试器附加
ptrace(PT_DENY_ATTACH, 0, 0, 0);

// 2. 禁止 core dump
setrlimit(RLIMIT_CORE, 0);

// 3. 清除动态库注入变量
unsetenv("DYLD_INSERT_LIBRARIES");
unsetenv("DYLD_LIBRARY_PATH");
// ... 清除所有 DYLD_* 变量

Windows

// 禁止调试器附加
SetProcessDebugPort(GetCurrentProcess(), (HANDLE)-1);

任何一步失败,进程直接退出,确保进程要么安全启动,要么不启动:

const PRCTL_FAILED_EXIT_CODE: i32 = 5;
const PTRACE_DENY_ATTACH_FAILED_EXIT_CODE: i32 = 6;
const SET_RLIMIT_CORE_FAILED_EXIT_CODE: i32 = 7;

5. 第三层:沙箱隔离

前两层防护控制"能执行什么命令"和"进程是否安全",第三层则限制"命令能访问什么资源"。即使恶意命令被执行,沙箱也能将其损害控制在有限范围内。

5.1 设计原则

  1. 默认拒绝:所有访问默认禁止
  2. 白名单开放:显式声明需要的权限
  3. 敏感路径保护.git, .codex 强制只读

5.2 Linux 实现

Linux 沙箱由多个内核特性组合实现:

Namespace:资源隔离

Namespace 是 Linux 内核提供的隔离机制,让进程看到的是"虚拟化"的系统视图:

Namespace 类型 隔离内容
Mount 文件系统挂载点
PID 进程 ID
Network 网络栈(网卡、路由、iptables)
User 用户和组 ID
UTS 主机名和域名

容器技术(Docker、Podman)本质上就是组合使用各种 namespace。

seccomp:系统调用过滤

seccomp(Secure Computing Mode)用于限制进程可调用的系统调用。进程被 seccomp 限制后,调用被禁止的系统调用会被内核直接终止:

// 示例:只允许 read, write, exit
struct sock_filter filter[] = {
    BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
    BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_read, 0, 2),
    BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 1),
    BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
};

Codex 禁止的系统调用:

调用 原因
ptrace 攻击其他进程
process_vm_readv 读取其他进程内存
process_vm_writev 写入其他进程内存
io_uring_* 可绕过安全检查
kexec_load 加载内核
init_module 加载内核模块

网络相关的精细控制:

// socket() 调用根据 domain 过滤
if (domain == AF_INET || domain == AF_INET6) {
    return EPERM;  // 禁止网络 socket
}
if (domain == AF_UNIX) {
    return allow();  // 允许 Unix socket
}

Bubblewrap:文件系统隔离

Bubblewrap(bwrap)是 Flatpak 项目开发的轻量级沙箱工具,通过组合 namespace 实现文件系统隔离。相比 Docker,它更轻量,无需 daemon,适合桌面应用沙箱化。

┌─────────────────────────────────────────────────────────────┐
│  主机系统                                                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  bwrap 创建的隔离环境                                │   │
│  │  • 独立的 mount namespace(文件系统视图)            │   │
│  │  • 独立的 user namespace(用户 ID 映射)            │   │
│  │  • 独立的 pid namespace(进程 ID 隔离)              │   │
│  │  • 可选的 network namespace(网络隔离)             │   │
│  │                                                     │   │
│  │  内部进程看到的文件系统:                            │   │
│  │  /bin/    → 主机 /bin/(只读)                      │   │
│  │  /home/   → 主机 /home/(只读)                     │   │
│  │  /project/ → 主机 /home/user/project/(可写)       │   │
│  │  /etc/passwd → 不可见                               │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Bubblewrap 参数构建

bwrap \
  --new-session              # 创建新会话
  --die-with-parent          # 父进程退出时终止
  --unshare-user             # 用户命名空间隔离
  --unshare-pid              # PID 命名空间隔离
  --unshare-net              # 网络命名空间隔离(可选)
  --proc /proc               # 挂载 /proc
  --ro-bind / /              # 根文件系统只读
  --dev /dev                 # 最小 /dev(含 urandom)
  --bind /project /project   # 项目目录可写
  --ro-bind /project/.git /project/.git  # .git 只读
  --chdir /project           # 设置工作目录
  -- command...

挂载顺序(重要):后挂载的会覆盖先挂载的,实现细粒度控制:

1. --ro-bind / /              # 根只读
2. --dev /dev                 # 最小 /dev
3. --bind /project /project   # 可写目录覆盖
4. --ro-bind /project/.git    # 子目录再次只读(覆盖可写)
5. --tmpfs /blocked           # 遮蔽禁止访问的路径

Landlock:备选方案

Landlock 是 Linux 5.13+ 内核特性,提供细粒度的文件系统访问控制。当 Bubblewrap 不可用时,Codex 会回退到使用 Landlock。

5.3 macOS 实现:Seatbelt

macOS 使用内置的 Seatbelt 沙箱机制(又称 App Sandbox),通过 /usr/bin/sandbox-exec 执行命令。Seatbelt 使用 SBPL(Seatbelt Policy Language)编写策略,内核强制执行,进程无法绕过。

SBPL 示例

(version 1)

; 默认拒绝所有操作
(deny default)

; 允许执行程序
(allow process-exec)

; 文件系统权限
(allow file-read* (subpath "/System"))
(allow file-read* (subpath "/usr"))
(allow file-read* (subpath "/Users/user/project"))
(allow file-write* (subpath "/Users/user/project"))

; 保护敏感目录
(deny file-write* (subpath "/Users/user/project/.git"))

; 网络权限
(deny network*)
(allow network-outbound (to "registry.npmjs.org"))
(allow network-outbound (to unix-socket))

常用规则

规则 说明
(deny default) 默认拒绝所有
(allow process-exec) 允许执行程序
(allow file-read* (subpath "...")) 允许读取指定目录
(allow file-write* (subpath "...")) 允许写入指定目录
(deny file-write* (subpath "...")) 禁止写入指定目录(覆盖 allow)
(allow network-outbound (to "...")) 允许出站网络连接

5.4 网络隔离模式

模式 行为 使用场景
FullAccess 不隔离网络 需要完整网络访问
Isolated 完全禁止网络 离线任务
ProxyOnly 通过本地代理 只允许白名单域名

ProxyOnly 模式下,bwrap 创建网络命名空间,启动代理进程路由流量。

5.5 平台对比

特性 Linux macOS
文件隔离 Bubblewrap Seatbelt
网络隔离 seccomp + namespace Seatbelt
系统调用过滤 seccomp 无(依赖 Seatbelt)
用户隔离 user namespace 无(依赖 Seatbelt)

6. Secrets 管理

前三层防护聚焦于命令执行的边界控制,但 AI 运行过程中还有一类风险:敏感信息的存储和泄露。Codex 通过独立的 Secrets 模块解决这个问题,该模块与三层架构并行运作。

6.1 敏感信息存储

用户通过 codex secrets set 命令存储敏感信息(如 API Key、数据库密码):

# 存储全局 secret
codex secrets set OPENAI_API_KEY

# 存储项目级 secret
codex secrets set DATABASE_URL --env my-project

存储流程:

用户输入: sk-xxxxxxxxxxxxxxxx
        │
        ▼
┌─────────────────────────────────────────────────────────────────┐
│  Secrets Backend 选择                                            │
│                                                                 │
│  优先级:                                                        │
│  1. OS Keyring(推荐)                                          │
│     • macOS: Keychain                                           │
│     • Windows: Credential Manager                               │
│     • Linux: Secret Service (GNOME Keyring / KWallet)          │
│  2. 本地加密文件(备选)                                         │
│     • 位置: ~/.codex/secrets/local.age                          │
│     • 加密: age 加密库                                          │
│     • 密钥: 存储在 OS Keyring                                    │
└─────────────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────────────┐
│  存储结构                                                        │
│                                                                 │
│  Keyring:                                                       │
│    Service: "codex"                                             │
│    Account: "global/OPENAI_API_KEY" 或 "env/<id>/DATABASE_URL"  │
│    Password: <加密后的主密钥>                                    │
│                                                                 │
│  local.age:                                                     │
│    {                                                            │
│      "version": 1,                                              │
│      "secrets": {                                               │
│        "global/OPENAI_API_KEY": "sk-xxxxxxxx",                 │
│        "env/my-project/DATABASE_URL": "postgres://..."         │
│      }                                                          │
│    }                                                            │
└─────────────────────────────────────────────────────────────────┘

为什么使用 OS Keyring?

6.2 输出脱敏

敏感信息可能通过多种途径泄露:AI 输出包含 API Key、错误消息暴露密码、日志记录 token。Codex 在输出前自动检测并脱敏敏感信息。

检测规则

// OpenAI API Key
OPENAI_KEY_REGEX: sk-[A-Za-z0-9]{20,}

// AWS Access Key ID
AWS_ACCESS_KEY_ID_REGEX: AKIA[0-9A-Z]{16}

// Bearer Token
BEARER_TOKEN_REGEX: Bearer [A-Za-z0-9._\-]{16,}

// 通用敏感赋值
SECRET_ASSIGNMENT_REGEX: 
    (api_key|token|secret|password) [:=] "...value..."

脱敏流程

AI 输出: "Your API key sk-proj-xxxxxxxxxxxxxxxx is ready"
        │
        ▼
┌─────────────────────────────────────────────────────────────────┐
│  redact_secrets() 函数处理                                      │
│                                                                 │
│  1. 匹配 OPENAI_KEY_REGEX → 替换为 [REDACTED_SECRET]           │
│  2. 匹配 AWS_ACCESS_KEY_ID_REGEX → 替换为 [REDACTED_SECRET]    │
│  3. 匹配 BEARER_TOKEN_REGEX → 替换为 Bearer [REDACTED_SECRET]  │
│  4. 匹配 SECRET_ASSIGNMENT_REGEX → 替换为 xxx=[REDACTED_SECRET]│
└─────────────────────────────────────────────────────────────────┘
        │
        ▼
终端输出: "Your API key [REDACTED_SECRET] is ready"

6.3 与沙箱的协作

Secrets 管理与沙箱机制协同工作:

  1. 进程加固确保 secrets 存储在 keyring 中的密钥不被 ptrace 读取
  2. 沙箱隔离限制 secrets 文件只能被 codex 进程访问
  3. 输出脱敏在 TUI 显示前自动执行,防止泄露到终端或日志

7. 完整执行流程

AI 请求: npm install lodash
        │
        ▼
┌─────────────────────────────────────────────────────────────────┐
│ 第一层:执行策略                                                 │
│                                                                 │
│ 1. 命令安全检查: npm 不在白名单,也不在黑名单                   │
│ 2. 规则匹配: npm install → Allow                               │
│ 3. Shell MCP 准备:                                              │
│    - 设置 EXEC_WRAPPER=/opt/codex/codex-execve-wrapper         │
│    - 创建 Unix Socket,fd=3                                     │
│    - 设置 CODEX_ESCALATE_SOCKET=3                              │
│ 4. 启动 Shell: bwrap ... bash-fork -lc "npm install lodash"    │
└─────────────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────────────┐
│ Shell 内部                                                      │
│                                                                 │
│ bash 解析命令 → 找到 npm                                        │
│ 执行 execve("/usr/bin/npm", ["npm", "install", "lodash"], env) │
│                                                                 │
│ 打补丁的 bash 检测到 EXEC_WRAPPER:                              │
│ → execve(EXEC_WRAPPER, ["/usr/bin/npm", "npm", "install", ...])│
└─────────────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────────────┐
│ codex-execve-wrapper                                            │
│                                                                 │
│ 1. 从 argv 获取: file="/usr/bin/npm", argv=["npm", ...]        │
│ 2. 通过 fd=3 发送 EscalateRequest 到主进程                      │
│ 3. 主进程检查规则,返回 EscalateResponse { action: Run }        │
│ 4. wrapper 执行 execve("/usr/bin/npm", ...)                     │
└─────────────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────────────┐
│ 沙箱内执行                                                      │
│                                                                 │
│ /usr/bin/npm install lodash                                     │
│ - 可读: / (整个文件系统)                                        │
│ - 可写: /home/user/project                                      │
│ - 只读: /home/user/project/.git                                 │
│ - 网络: 可访问 registry.npmjs.org                               │
└─────────────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────────────┐
│ 输出处理                                                        │
│                                                                 │
│ npm 输出 → redact_secrets() → 终端显示                          │
│ (如有 API Key 会自动替换为 [REDACTED_SECRET])                 │
└─────────────────────────────────────────────────────────────────┘

8. 安全边界总结

层级 防护目标 实现机制 失效时影响
第一层 控制哪些命令能执行 命令检查 + 规则匹配 + execve 拦截 第二层仍能保护进程
第二层 保护进程本身不被攻击 ptrace 禁止 + 环境清理 第三层仍能限制资源访问
第三层 限制命令能访问的资源 namespace + seccomp + Seatbelt 最后防线
Secrets 保护敏感信息存储和输出 OS Keyring + age 加密 + 输出脱敏 独立于三层架构

参考资料