Codex Skill 里不应该明文保存密钥

有些配置看起来很像普通文档内容。

比如一个 Figma Personal Access Token。它只是为了让本地脚本调用 Figma REST Images API,把设计节点导成 PNG;放进 Skill 里,后续每次执行都不用再问,看起来最省事。

但这类值不应该写进 Skill。Skill 是可复用的长期指令,密钥是会过期、会泄露、需要轮换的私有凭据。把两者混在一起,短期方便,长期会把风险带进仓库、备份、日志、Agent 上下文和后续迁移里。

这里整理一次真实决策:Codex 需要使用 Figma token 导出图片,但不把 token 明文写进 Skill,而是放到本机私有 env 目录里,再让 Skill 只记录读取规则和过期提醒。

Skill 是规则,不是保险柜

Codex Skill 的定位是「让下一次 Agent 知道怎么做」。

它适合保存流程、规则、命令模板、路径约定、失败边界和经验教训。例如「Figma 导图优先走 REST Images API」「导出后检查尺寸和透明角」「如果接口返回 Invalid token,先判断认证问题,不要误判为节点导出失败」。

它不适合保存真实 token。

原因主要有四个。

第一,Skill 是长期文本。它可能被复制、打包、同步、备份,也可能进入 Git 仓库。密钥一旦写进去,就很难确定后来经过了哪些路径。

第二,Skill 会被 Agent 读取。只要未来某次任务触发这个 Skill,密钥就可能进入上下文、日志或中间摘要。就算 Agent 没有主动打印,明文也已经出现在处理链路里。

第三,Skill 通常是跨任务复用的。一个 token 本来只服务 Figma 导图,却可能因为 Skill 被别的任务读取而扩大暴露面。

第四,密钥有生命周期。Figma Personal Access Token 当前最长只有有限有效期;API key 也应该定期轮换。把短生命周期的东西写进长期规则,会让规则不断过期,也容易让失效 token 被误当成流程问题。

更稳的分层是:

类型 适合放哪里 例子
长期规则 Skill / AGENTS.md / README 导图优先级、失败判断、检查命令
本机私有凭据 ~/.codex/env/<skill>.env / Keychain FIGMA_TOKENAPIFOX_ACCESS_TOKEN
团队生产凭据 KMS / 云平台 Secret / CI Secret 生产 API key、部署密钥
临时运行参数 shell env / CLI 参数 本次节点 ID、输出路径、是否 dry-run

这个分层的核心,是把不同生命周期和不同暴露面的东西拆开。env 文件只是本机私有配置,不是绝对安全的保险柜。

官方建议保持一致

OpenAI 的 API key 安全建议很直接:不要把 key 提交到仓库,推荐用环境变量;生产环境还应考虑 Key Management Service。OpenAI 的 Quickstart 也默认让 SDK 从 OPENAI_API_KEY 这类环境变量读取密钥。

OpenAI:Best Practices for API Key Safety 明确提醒不要把 API key commit 到 repository,并建议用环境变量替代代码里的明文 key;生产环境可以考虑 KMS。

Anthropic 的建议也类似。它把 API key 泄露的常见来源指向公开仓库和第三方工具,建议云环境使用加密 Secret,本地如果用 dotenv,要把 .env 放进忽略列表;它还建议按计划轮换 key,例如 90 天一次,并尽量按用途拆分不同 key。

Anthropic:API Key Best Practices 提到不要在代码或配置文件里直接包含 key;本地 dotenv 要从版本控制排除,云环境优先使用 encrypted secret storage。

Figma 的文档则强调 Personal Access Token 是代表个人账号访问 API 的凭据。它可以用于个人脚本和本地工具,生成后只显示一次,不再需要时应撤销。Figma REST API 的认证文档也说明,个人脚本适合使用 Personal Access Token,读取文件内容需要 file_content:read scope。

Figma REST API Authentication 把 Personal Access Token 定位为个人脚本和本地工具的认证方式;Figma Help Center 说明 token 生成后只显示一次,并可以在不再使用时撤销。

Cursor 的安全文档没有规定「本地 env 应该放哪里」,但它提醒了 AI 开发工具里的关键边界:开发环境和代码数据会进入工具处理链路,安全边界需要被明确管理。即使工具提供 Privacy Mode,也不等于可以把密钥当普通文本到处放。

Cursor Security 说明了它对开发环境、代码数据、Privacy Mode 和最小权限的处理方式。对本地 Agent 场景来说,关键启发是:敏感内容要尽量减少进入 AI 请求、索引、日志和长期文本的机会。

这些建议背后的共识很稳定:密钥应该作为运行时凭据管理,而不是写进源码、长期文档或可复用指令里。

为什么不是直接用 shell 环境变量

最标准的做法是 export FIGMA_TOKEN=...

这个方式没问题,但对 Codex 这类长期本机工作流来说,它有两个小麻烦。

第一,不同 shell session 不一定共享。今天在一个终端 export 过,明天 Codex 新开任务时可能已经没有这个变量。

第二,变量归属不清楚。如果所有工具都塞进 ~/.zshrc,后续查起来会变成一长串混杂配置:Figma、APIFox、TinyPNG、OSS、各种测试 token 全在一起。

这里采用一个折中方案:在 Codex 自己的本机目录下建立私有 env 文件夹。

~/.codex/env/
  figma-tinypng-assets.env
  apifox-mcp.env
  tinypng-assets.env

每个文件按 Skill 命名,格式仍然是普通 .env

FIGMA_TOKEN=...
FIGMA_TOKEN_EXPIRES_AT=2026-09-02
FIGMA_TOKEN_RENEW_REMIND_AT=2026-08-26

Skill 只记录「从这个文件读取 FIGMA_TOKEN」,不记录真实值。这样下一次执行时,Codex 能找到配置;如果需要迁移,也能看懂哪些 Skill 依赖本机私有配置。

这个目录应该怎么保护

~/.codex/env 不是生产级 KMS。它只是本机私有配置目录。

它至少要满足几个条件。

第一,目录和文件权限要收紧。

mkdir -p "$HOME/.codex/env"
chmod 700 "$HOME/.codex/env"
chmod 600 "$HOME/.codex/env/figma-tinypng-assets.env"

700 表示只有当前用户能进入目录;600 表示只有当前用户能读写文件。这样不能防住所有风险,但可以避免同机其他用户或误配置脚本随手读取。

第二,不要把这个目录加入 Git 仓库。

~/.codex/env 放在 home 目录下,本来就不应该在业务仓库里。即使未来要备份 Codex 数据,也要把 env 目录单独排除,或者只备份模板文件。

第三,脚本只能验证「存在」「是否过期」「能不能访问接口」,不要打印真实值。

可以这样写:

if [ -f "$HOME/.codex/env/figma-tinypng-assets.env" ]; then
  echo "figma env: present"
else
  echo "figma env: missing"
fi

不要这样写:

cat "$HOME/.codex/env/figma-tinypng-assets.env"

第四,过期时间也要写进配置。

FIGMA_TOKEN_EXPIRES_AT=2026-09-02
FIGMA_TOKEN_RENEW_REMIND_AT=2026-08-26

这两个值不是密钥,可以出现在 Skill 或提醒里。它们能帮助 Agent 在执行前判断 token 是否快过期,避免把过期认证误判成接口、节点或脚本问题。

一个具体例子:Figma 导图

这次的真实问题是:需要把 Figma 节点导成 2x PNG。手动操作很简单,选中节点,右侧 Export 选 2x PNG,点击导出。

为了自动化这件事,最稳的路径是 Figma REST Images API。

curl \
  -H "X-Figma-Token: $FIGMA_TOKEN" \
  "https://api.figma.com/v1/images/<FILE_KEY>?ids=<NODE_ID>&format=png&scale=2"

这里有两个细节很容易踩坑。

第一,Figma Personal Access Token 要用 X-Figma-Token header。至少在这次验证里,同一个 token 用 Authorization: Bearer 会返回 Invalid token

第二,接口第一步返回的是图片 URL,不是直接返回 PNG 文件。脚本拿到 URL 后要立刻下载到本地,再做尺寸、透明角和可见内容检查。图片 URL 有时效性,不能把它当长期资源。

这段逻辑对应的 Skill 规则应该写成这样:

- Figma REST Images API 默认从 `$HOME/.codex/env/figma-tinypng-assets.env` 读取 `FIGMA_TOKEN`- 使用 `X-Figma-Token` header 调用 API。
- 如果返回 `Invalid token` / `Unauthorized` / `Forbidden`,先判断认证问题,不要误判成节点导出失败。
- 导出后检查 PNG 类型、物理尺寸、四角 alpha 和可见像素范围。

注意,这里没有任何真实 token。Skill 保存的是操作协议,不是凭据本体。

什么时候应该升级到 Keychain 或 KMS

~/.codex/env 适合个人本机、内部临时工具和低频脚本。它的优点是直观,Codex 容易读取,按 Skill 分文件也容易维护。

但它不是所有场景的终点。

如果凭据很敏感,或者它能操作真实生产环境,就应该优先放到系统级凭据管理里。macOS 上可以考虑 Keychain;团队云环境里应该使用 AWS Secrets Manager、GCP Secret Manager、Azure Key Vault、Vercel Environment Variables、GitHub Actions Secrets 等。

如果脚本要在 CI/CD 里跑,就不要依赖 ~/.codex/env。CI 应该从平台 Secret 注入环境变量,脚本仍然只读取变量名。

如果 token 需要多人共用,也不要把个人 PAT 复制给别人。Figma 文档里也区分了个人 token、组织级 plan access token 和 OAuth app。个人本地脚本可以用 PAT,团队自动化更适合组织级或 OAuth 机制。

可以按场景判断:

场景 推荐方式
个人本机 Skill 脚本 ~/.codex/env/<skill>.env
高敏感本机凭据 macOS Keychain / 1Password CLI
CI/CD GitHub Actions Secrets / 云平台 Secret
生产服务 KMS / Secret Manager
多用户 SaaS 集成 OAuth
组织级自动化 组织级 access token 或平台托管凭据

给 Agent 的规则要写清楚

这类机制真正要防的,是下一次 Agent 不知道边界。

所以 Skill 里应该明确写几类规则。

第一,密钥来源。

默认从 `$HOME/.codex/env/<skill-name>.env` 读取,不从 Skill 正文读取真实 token。

第二,日志边界。

只输出 token 是否存在、是否过期、接口认证是否成功,不输出 token 值。

第三,失败归因。

认证失败时,先报告 token 失效或权限不足,不要继续尝试和认证无关的本地拼接方案。

第四,轮换提醒。

如果 env 文件里有 `*_EXPIRES_AT`,到期前一周提醒用户重新生成。

第五,备份边界。

备份 Codex 数据时默认排除 `$HOME/.codex/env`,只备份 env 示例模板。

这些规则看起来啰嗦,但对 Agent 很有用。因为 Agent 不会天然知道「这个文件是规则,那个文件是凭据」。边界需要写出来。

底线

~/.codex/env 不是为了替代所有安全工具。

它解决的是个人本机 Codex 工作流里的一个具体问题:Skill 需要知道怎么读取凭据,但 Skill 自己不能保存凭据。

底线很简单:

  • Skill 里只写变量名、路径、读取方式、权限要求和失败判断。
  • env 文件里可以写真实值,但必须放在本机私有目录并限制权限。
  • 终端输出、文章、日志、Git diff、对话回复里都不要出现真实密钥。
  • 过期时间和提醒时间可以写进 Skill,因为它们不是密钥。
  • 一旦发现密钥进入仓库或对话摘要,要按泄露处理,立刻撤销并重新生成。

这个边界清楚以后,Codex 后续使用 Figma、APIFox、TinyPNG 或其他本地工具时,就不需要在「方便」和「安全」之间反复拉扯。

方便的部分交给统一读取规则;敏感的部分留在本机私有配置里。