关于 dazai — burn-after-reading secret (motokano)
面向需要限制密钥读取次数或绑定 Shell/SSH 会话生命周期的 Agent,提供 Rust 密钥管理工具。其 MCP 服务从锁定内存提供密钥,并可在会话结束时擦除密钥、终止进程。
主要功能
- 01通过 MCP 提供密钥
- 02达到指定读取次数后擦除密钥
- 03通过心跳将守护进程绑定到会话
- 04会话中断时终止已注册的 Agent 进程
- 05锁定内存及 Linux seccomp 隔离
适用场景
- 01向 Agent 提供一次性 API 密钥
- 02在 Shell 或 SSH 会话结束时清除密钥
- 03会话中断后停止已注册的 Agent
MCP 相关
`motokano` 将已配置工具作为一次性 MCP 服务提供;`dazai mcp` 允许 MCP 客户端注册进程 ID,以提供会话绑定保护。两者均使用 stdio 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
ningen-shikkaku
为 AI Agent 提供阅后即焚的密钥。
ningen-shikkaku 提供两个小型 Rust 二进制程序——dazai(与会话绑定的守护进程)和 motokano(自我销毁的一次性 MCP 服务)。
你的 MCP 配置中到处都是明文 API 密钥,而你运行的每个 Agent 都能读取所有密钥——并且即使 Agent 结束运行,这些密钥仍会继续有效。dazai 颠覆了这种做法:密钥存放在锁定且不可交换的 RAM 中,通过 MCP 提供给 Agent,并且会在读取 N 次后销毁,或者在会话结束的那一刻立即销毁。

motokano --calls 1 --tool 'name=get_key,kind=static,value=s3cr3t' --arm
将任意 MCP 客户端指向它,并调用一次 get_key → 你会收到 s3cr3t
→ 服务会从锁定内存中擦除该值,并向自身发送 SIGKILL。再次调用
→ 进程已不存在。
安装
# prebuilt binaries (macOS arm64/x86_64, Linux x86_64/arm64)
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/New1Direction/ningen-shikkaku/releases/latest/download/dazai-installer.sh | sh
# or homebrew
brew install New1Direction/tap/dazai New1Direction/tap/motokano
# or from source (required for the Linux seccomp build)
git clone https://github.com/New1Direction/ningen-shikkaku
cd ningen-shikkaku/rs
cargo build --release # -> target/release/{dazai, motokano}
cargo build --release --features seccomp # Linux: seccomp syscall allowlist
预构建二进制程序使用默认功能构建;受 seccomp 限制的守护进程需要从源代码构建(它会链接 libseccomp——请先安装 libseccomp-dev +
pkg-config)。
与 Claude Code 搭配使用
# a one-shot secret an agent can read exactly once:
claude mcp add burn-once -- motokano --calls 1 --arm \
--tool 'name=get_key,kind=static,value=YOUR-SECRET'
# or the session-bound daemon: agents register their PID and get SIGKILLed
# the moment your session dies
dazai daemon --arm --grace 5 &
claude mcp add dazai -- dazai mcp
任何 MCP 客户端都能以相同方式工作——传输方式是纯 stdio。
第二幕:为你的 Agent 设置死亡开关
同一个守护进程也是会话终止开关。任何 MCP 客户端都可以注册其 PID;
当你的 shell/SSH 会话结束、心跳停止或收到紧急信号时,dazai 会向所有已注册进程发送 SIGKILL,用编译器无法优化掉的擦除操作覆写密钥,然后退出。转身离开:Agent
消亡,密钥焚毁。
dazai daemon --ping-timeout 15 # terminal A (dry-run by default; --arm makes it real)
dazai client --interval 5 # terminal B
# close terminal B -> the daemon wipes its secrets and exits
它只在你自己的机器上运行,处理你自己的密钥和你自己配置的 工具。它绝不会触碰其他进程、文件或主机。
包含内容
它分为两层:
- 经过强化的 Rust 守护进程 + 工具——真正的实现:
mlock(不使用交换空间)、madvise(MADV_DONTDUMP)+prctl(PR_SET_DUMPABLE, 0)(不生成核心转储 / 不允许 ptrace)、seccomp 系统调用允许列表(禁止execve/open/connect/…),以及 不可省略的explicit_bzero/memset_s擦除操作;以及 - Python 参考实现——最初用于验证该机制的概念验证(见
python-reference.md)。
| 组件 | 功能 |
|---|---|
dazai daemon | 看门狗:保存经过 mlock 锁定的密钥 + UNIX 套接字心跳;在会话丢失时擦除密钥并自我销毁。在 Linux 上受 seccomp 限制。 |
dazai client | 心跳客户端——将守护进程的生命周期与 shell / SSH 会话绑定。 |
dazai mcp | 一个将守护进程作为工具提供的 MCP 服务,任何 Agent 都可以注册自己的 PID,以获得与会话绑定的保护(如果会话结束,该进程会收到 SIGKILL)。 |
motokano | 独立的自我销毁型 MCP 服务:处理 N 次工具调用,然后擦除密钥状态并退出。 |
| Python 参考实现 | secmem.py / deadman.py / heartbeat.py / shellrc.sh——可移植的概念验证。 |
架构
flowchart LR
A["MCP client / AI agent<br/>(stdio transport)"]
subgraph Daemon["dazai daemon (kikka Watchdog)"]
D["dazai daemon<br/>mlock'd SecretBuffers (goodnight)<br/>seccomp-confined on Linux (kekkai)"]
SOCK[("UNIX socket 0600<br/>HELLO heartbeat + REGISTER / ARM / STATUS")]
end
MCPD["dazai mcp<br/>(rei · rmcp server)"]
HB["dazai client<br/>(heartbeat: HELLO / PING)"]
MOTO["motokano<br/>(self-immolating MCP server)<br/>static values in SecretBuffer"]
KILL{{"wipe (explicit_bzero / memset_s)<br/>+ SIGKILL"}}
A -->|"register pid / status / panic"| MCPD
A -->|"get_key (static, N reads)"| MOTO
MCPD -->|"relay verbs + signals via pidfile"| SOCK
HB -->|"holds liveness connection"| SOCK
SOCK --- D
MOTO -. "optional --dazai-socket: register + monitor" .-> SOCK
D ==>|"on trigger: SIGKILL registered PIDs, then wipe + self-SIGKILL"| KILL
MOTO ==>|"after N calls / EOF / daemon death: wipe + exit"| KILL
HB -. "drop / ping-timeout / panic signal" .-> D
Korg 互操作
dazai daemon 和 motokano 可以将数据写入 Korg
防篡改账本:--korg-sink PATH(对于预先打开的描述符,也可使用 /dev/fd/N)会在每个启用、会话、读取、擦除
和终止步骤中追加一条符合 Korg 追加格式的记录。记录仅包含固定词汇表字段和计数器。绝不会记录密钥
值、长度、摘要、工具名称、参数、路径或环境信息。Korg 会通过其 ningen-shikkaku.lifecycle@v2
封装配置文件导入该文件,并分配序列号、哈希和签名。请参阅 Korg 生命周期记录。
威胁模型
daZai 缩小了明文密钥可被访问的时间窗口和攻击面,并确保会话结束时将其确定性地销毁。
它可以防护以下风险:
| 风险 | 方式 |
|---|---|
| 密钥被换出到 swap | mlock 将缓冲区锁定在 RAM 中 |
| 密钥被捕获在核心转储中 | madvise(MADV_DONTDUMP) + prctl(PR_SET_DUMPABLE, 0)(Linux) |
| 会话丢失导致密钥仍留在内存中 | 心跳中断/登出 → 擦除 + SIGKILL |
| 密钥使用后残留在进程内存中 | explicit_bzero / memset_s — 编译器可能不会省略的擦除操作 |
| 受限进程逃逸 | seccomp 允许列表拒绝 execve / open / connect / ptrace / …(Linux) |
| 通过 ptrace 窥探守护进程 | prctl(PR_SET_DUMPABLE, 0)(Linux) |
它不能防护以下情况(项目对此刻意保持坦诚):
- GPU VRAM。 如果接入的 LLM/Agent 将密钥复制到 GPU 内存,终止主机进程也不会擦除 VRAM。daZai 控制主机 RAM 及其监管的进程,而不控制加速器的内存。
exec工具的标准输出。motokano的kind=exec工具会返回命令的标准输出,该输出由操作系统缓冲,且不会保存在锁定缓冲区中。需要擦除保障时,请使用kind=static(预加载、已锁定且可擦除的值)。- 托管运行时残留(Python 参考实现)。 CPython 会随意复制
bytes,因此密钥在锁定缓冲区之前/之后可能会暂时存在于未锁定的堆中。Rust 实现消除了自身缓冲区中的这一问题(数据写入锁定映射,绝不会复制到 GC 堆);Python 层是参考实现,不提供硬性保证。 - 在运行中的机器上拥有特权或相同 UID 的攻击者(root、
/proc/<pid>/mem、调试器)在擦除之前读取内存。mlock可阻止换出,但不能阻止读取内存;seccomp +PR_SET_DUMPABLE会提高 Linux 上的攻击门槛,但已拥有运行中机器特权访问权限的攻击者不在防护范围内。 - 对 RAM 的冷启动/DMA/物理攻击。
- 严重崩溃(内核 OOM、外部
kill -9、断电):擦除路径无法执行,因此不会将任何内容清零。此类情况下该机制只能尽力而为,绝不声称能做到更多。
简而言之:daZai 并非、也不可能保证防范已经控制你运行中机器的攻击者。它是一种强力工具,可让密钥短暂存在并绑定到会话,同时明确说明所有限制。
验证
- Rust 工作区中有 81 项测试(安全内存、panic 策略、线协议、MCP 层、一次性生命周期、Korg 生命周期契约),另有 Python 参考实现的 29 项测试。
- Linux seccomp 在真实的
KillProcess过滤器下通过了两种架构的验证 —aarch64(本地)和x86_64(CI)— 守护进程会安装正在生效的过滤器,完整集成测试套件也会在该过滤器下运行,且没有出现SIGSYS。 - 每次推送都会运行完整测试套件(默认配置和
--features seccomp)、clippy -D warnings,并在 x86_64 Linux 上运行rustfmt --check,作为长期回归检查门禁。
深入的技术文档(各 crate 的设计、seccomp 允许列表、对抗性审查历史)位于 rs/README.md;Python 概念验证位于 python-reference.md。
名称由来
名称取自小说家 太宰治。他的作品反复探讨消失与自我抹除的主题,这很适合这样一种软件:一旦不再有人看护,就会立刻将自身抹除。仓库以他的小说《人间失格》(人間失格,Ningen Shikkaku)命名。这只是风格上的呼应,并非宣言;软件只会按指令自毁。
许可证
MIT © 2026 New1Direction。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。