← 返回主报告:Kimi Agent(云端沙箱)技术报告 | GitHub 原文
合规与风险声明:本报告为安全研究与互操作学习目的的逆向分析,全程只读采集,未对目标系统做任何修改;文中所有密钥、token、账号级标识(chat_id / project_id / tenant_id 等)均已脱敏;沙箱内发现的默认弱口令(VNC/SSH)属平台侧配置,仅作安全发现披露,请勿用于访问任何不属于自己的系统。docx/pdf/xlsx/kimi-slides 等引擎二进制为 Moonshot 专有许可(禁再分发/逆向),本文仅作行为级描述。报告基于单次分析窗口(约 50 分钟生命周期),软件版本与技能库存随镜像更新可能变化。
取证时间:2026-08-18。访问方式:SSH(kimi 用户只读)+ root 级 HTTP 文件服务兜底(127.0.0.1:18080)。 沙箱全程未做任何修改。
0. 总览:三层存储架构
沙箱的文件持久化由三个独立层次组成,互不重叠:
| 层 | 挂载点 | 后端 | 读写 | 内容 | 持久性 |
|---|---|---|---|---|---|
| 容器根 | /(overlay2) | 宿主机块设备 /run/blk-cube/vdc/0..60 + 可写层 vda/disk/2d9b504a.../upper | rw | 系统、应用代码 | 容器级(镜像层只读,upper 层是否跨重建持久未知) |
| portal overlay | /mnt/portal-overlay(fuse.portal) | 云端 PortalService(https://kimi-api-sandbox.msh.team/apiv2) | 只读(目录项 -r--r--r--、owner root) | 用户资产:skills、plugins、auth、vault、agent-gw 凭证、网站模板 | 云端持久(用户/租户级) |
| drive9 | /mnt/agents(fuse.drive9) | 内网 drive9 server http://10.213.5.144,路径 :/projects/<project-id> | 可读写 | 项目工作区(upload/output/temp 等) | 云端持久(项目级),close-sync 同步 |
另有 /workspace(空目录,kimi:kimi)与 /opt/moonbox-project-template/version.json 中声明的兼容路径。
证据(cat /proc/mounts 摘录):
overlay2 / overlay rw,relatime,lowerdir=/run/blk-cube/vdc/60:...:/run/blk-cube/vdc/0,
upperdir=/run/blk-cube/vda/disk/2d9b504a104a439f9374a6374a236fa7/upper,...
portal /mnt/portal-overlay fuse.portal rw,nosuid,nodev,relatime,allow_other,max_read=1048576
drive9 /mnt/agents fuse.drive9 rw,nosuid,nodev,relatime,allow_other,max_read=1048576
df -h:overlay2 41G(仅用 31M,刚重建);drive9 显示 1.0T 配额。
1. portal 二进制(/usr/local/bin/portal)
- ELF x86-64,52MB,Go 静态编译,stripped,构建于 2026-08-11。
portal --help揭示它是一个 FUSE overlay 文件系统,把云端各类用户资产挂到本地一个挂载点,关键 flags:
-agentgw Mount the agent-gw client configuration file.
-auth Mount the user's persistent CLI/plugin credentials.
-configured_readonly Mount KimiAPI-configured public read-only directories.
-evo_sessions Mount a Skill-Evo job's candidate-session overlay (evo sandbox only).
-plugins Mount the user's installed plugins.
-skills Mount the user's installed skills.
-upload Mount the chat upload directory.
-vault Mount the user's dream vault.
-workspace Mount the chat workspace as the writable root.
-http-bind Enable HTTP server for chat bind API (-http-addr 默认 :8080)
-loopback / -loopback.root / -loopback.path Overlay local-only loopback directories(本地落盘、不回云)
-gateway-addr https://kimi-api-sandbox.msh.team/apiv2 (prod 默认)
-gateway-dev-addr https://kimi.kimi.team/apiv2 (dev 默认)
- 二进制 strings 显示它通过 connect-RPC 调
dev.msh.team/protos/kimi-go/kimi/portal/v1的 PortalService,方法包括:ValidateBindToken、GetAPIKey、GetS3Credentials、ListChatFiles、GetEvoSessionFile(s)、SetupApp、GetVault/GetVaultPage、GetAutoDream、GetWebsiteUrl/GetWebsiteInfra、GetBucketWebsite/PutBucketWebsite/DeleteBucketWebsite。即 portal 是 skills/plugins/凭证/vault/网站部署等多类云资产的统一”门面 FS”。
1.1 启动流程:空 manifest 启动 + claim 时绑定(s6 服务脚本 /etc/s6-overlay/s6-rc.d/portal/run)
脚本内注释直接写明了架构契约:
Go portal overlay service (bind-token STS contract). Boots with an EMPTY mount manifest and -http-bind (:8080): kimiwarden delivers the identity at claim time — POST /api/v1/bind_token (warden-signed HS256 JWT that portal exchanges for scoped STS via kimiapi PortalService), then POST /api/v1/bind with the overlay manifest (skills/plugins/auth/vault).
运行中的实际命令行(ps aux):
/usr/local/bin/portal -http-bind -allow-other -env prod \
-gateway-addr https://kimi-api-sandbox.msh.team/apiv2 /mnt/portal-overlay
- 启用门:
KIMI_PROJECT_PORTAL_CAPABILITY_ENABLED=true或旧信号KIMI_PROJECT_PORTAL_OVERLAY=1(由 kimiwarden / reception preset 注入)。 - 注释还提到旧的静态
K_OSS_*凭证已废弃(”fails closed”),一切授权走 claim 时 bind-token 换 STS。 - :8080 实测在线:
GET /→404 page not found,GET /api/v1/bind→Method not allowed(要 POST)。
1.2 /mnt/portal-overlay 内容结构
/mnt/portal-overlay/
├── .agent-gw.json (444 root, 只读;portal -agentgw 挂载)
├── .agents/plugins/ (portal -plugins:audio_generation, baidu-pan, china_standards,
│ cloudflare, github, ifind, image_generation, imf,
│ interactive-research-report-en, lark, musepool, scholar,
│ sec_edgar, sp_data, ...)
├── .user/
│ ├── auth/ (portal -auth:dws/, lark/ 两类凭证目录)
│ └── skills/ (portal -skills:用户安装的技能,如 engineering-ppt-converter,
│ openclaw-selfhost-ops, translation-review-coach 等 6 个)
├── .vault/ (portal -vault "dream vault",当前为空)
└── .websites-templates/ (portal -configured_readonly:13 个网站模板
0-origin, 1-cyber-rain-frontend, ..., 12-seaside-stay-fullstack;
每个目录含 <name>.zip + info.md)
.agent-gw.json 内容(凭证已脱敏):
{"api_key":"sk-kimi-8OQEd910...", // 存在:agent-gw API key,sk-kimi- 前缀
"base_url":"https://agent-gw.kimi.com/coding",
"kimi_chat_id":"1a014098-****-****-****-********15cb"}
.vault(”dream vault”)当前为空目录;.user/auth/dws 下有 .dws、.local 子目录(CLI/插件持久凭证存放点,未读内容)。
1.3 符号链接缝合(reception preset init_script 建立)
容器内大量”本地路径”实际是指向 portal overlay 或 drive9 的 symlink:
/app/.vault -> /mnt/portal-overlay/.vault
/app/.websites-templates -> /mnt/portal-overlay/.websites-templates
/app/.agents/plugins -> /mnt/portal-overlay/.agents/plugins
/mnt/agents/.agents/plugins -> /mnt/portal-overlay/.agents/plugins
/mnt/agents/.user/auth -> /mnt/portal-overlay/.user/auth
/mnt/agents/.user/skills -> /mnt/portal-overlay/.user/skills
/mnt/agents/.vault -> /mnt/portal-overlay/.vault
/mnt/agents/.websites-templates -> /mnt/portal-overlay/.websites-templates
注意:/app/.agents/skills 不是 symlink,是容器镜像内真实目录(预装公共技能集,约上百个),与 portal 挂的用户技能(/app/.user/skills)分离。
2. drive9(/usr/local/bin/drive9)— 可写项目存储
- ELF x86-64,19.7MB,Go 编译(go1.26.1),带 debug_info 未 strip。是个功能完整的存储/协作 CLI,子命令(
drive9 --help摘录):
create / delete / admin <tenant|pool> # 租户管理(TiDB Cloud 模式)
ctx show|add|import|fork|ls|use|rm # 上下文(身份);fork 是 copy-on-write
fs <command> # 文件系统操作
token issue|revoke # workspace-zone scoped token
vault set|get|put|with|ls|rm|grant|revoke|audit # 密钥 vault
journal new|append|cat|find|verify # append-only agent/workflow 日志
git clone --fast # git-aware 快速克隆
pack / unpack # 把本地 overlay 打包到 drive9/S3(快照迁移)
mount [flags] [:/remote] <mountpoint> # FUSE 挂载(另有 mount drain / mount vault)
profile show # 挂载 profile([local]/[remote] 过滤规则)
region list # 从 drive9 manifest 列出供应区域
doctor fuse / update # 诊断与自更新
二进制 strings 还暴露:shadow 写回缓存(writeback-cache、same-path-dirty、flush_debounced)、commit queue 冲突自动重试、SSE 缓存失效(SSE reset — invalidating all caches)、TiDB Cloud 物理共享池租户模型等。
2.1 实际挂载(ps aux)
/usr/local/bin/drive9 mount --foreground --mode=fuse -allow-other \
-readdir-prefetch --parallel-read-concurrency 8 --read-concurrency 48 \
--server http://10.213.5.144 --profile kimi-project --durability close-sync \
:/projects/1a01406e-****-****-****-********d0ce /mnt/agents
mount 日志(/tmp/kimi-project-drive9.log):
drive9: sync mode: strict
drive9: mounted on /mnt/agents (server: http://10.213.5.144,
actor: 0a8893244854f033a73bd4ade8bc0548, readonly: false,
write_policy: close-sync,
cache: /root/.cache/drive9,
shadow: /root/.cache/drive9/6504f2b4669187a6/shadow)
drive9: SSE reset — invalidating all caches
... flush upload failed for /output/frp-share/frpc.log:
Put "http://10.213.5.144/v1/fs/projects/1a01406e-****-****-****-********d0ce/output/frp-share/frpc.log": context canceled
说明:写策略 close-sync(close 时同步上传),本地 shadow 缓存在容器内 /root/.cache/drive9/;远端 API 形态是 PUT /v1/fs/projects/;SSE 推送用于缓存失效(多客户端一致性)。
2.2 /root/.drive9/ 配置与凭证
- 目录只有
profiles/kimi-project一个 profile,内容是[local]过滤清单(哪些路径只留在本地、不同步到云端):
[local]
.store/** **/.cache/** **/.git/** **/.gradle/** **/node_modules/**
**/target/** **/dist/** **/build/** **/coverage/** **/__pycache__/**
**/.venv/** **/tmp/** .kimi/** .agents/** .user/** .vault/** ...
即 node_modules、构建产物、git 内部、以及 .agents/.user/.vault(后者本来就由 portal overlay 提供)都不回传云端 —— 这是项目同步的关键策略。
- 凭证在服务 env 文件
/run/service/drive9-fuse/env(root 600 语义,经 HTTP 兜底读取):
HOME='/root'
DRIVE9_SERVER='http://10.213.5.144'
DRIVE9_API_KEY='drive9_ZXlKaGJHY2lPaUp...' # 存在:格式 drive9_<base64(JWT)>;
# JWT payload 含 tenant_id=890c103a-****-****-****-********625a、
# token_version=1、journal_permissions 列表、iat≈1785482181(2026-08-18 前后签发)
kimi 用户侧 ~/.drive9 无 context(drive9 ctx ls → “no contexts configured”),即只有 root 身份的 FUSE 守护进程持有凭证,沙箱内用户拿到的只是挂载视图。
2.3 s6 服务与 watchdog(/run/service/drive9-fuse/run、drive9-fuse-watchdog/run)
- 启动脚本:每次(重)启动前先
fusermount3 -uz清残留死挂载;若挂载点被非 drive9 占用则拒绝清理直接退出(防止误清)。启动间隔节流(<2s sleep 1)。 - watchdog:每 15s 探活
stat /mnt/agents/.+ls -U .drive9-health(专用小目录,避免大目录 readdir 触发预取回源);连续 3 次失败pkill -9 drive9交给 s6 重启;探活目录缺失时先mkdir -p自愈(真挂死时 mkdir 也会超时,不误放)。
2.4 /mnt/agents 内容
/mnt/agents/
├── .agents/ .user/ .vault .websites-templates # 全是 portal overlay 的 symlink(见 1.3)
├── .drive9-health/ # watchdog 探活目录
├── .tmp/ # drive9 内部暂存(root 700)
├── upload/ # 用户上传文件入口(当前空)
├── output/ # 产物出口;现有 output/frp-share/(frpc 客户端与日志 —— 即本分析所用 SSH 隧道的载体)
└── temp/ # 临时(当前空)
kernel-server(jupyter :8888)的 WORKDIR 就是 /mnt/agents;version.json 声明 workspace_path=/mnt/agents、project_output_dir=,并给出兼容路径集(/mnt/okcomputer、/mnt/kimi、/workspace/project、/app/.user/skills 等)。
3. /workspace
/workspace 是空目录(kimi:kimi, 0755,镜像自带),无任何内容、未被挂载、未被 s6 脚本或 /app 代码引用。version.json 的 compat_paths 里只提到 /workspace/project。判断:遗留兼容路径/保留挂载点,当前模板下不起作用,工作区已全部收敛到 /mnt/agents。
4. 项目 ID 与 kimi_chat_id 的关系
两个 ID 是不同对象、各自独立:
| ID | 值 | 语义 | 出现在 |
|---|---|---|---|
| project-id | 1a01406e-*---*****d0ce | drive9 项目工作区(:/projects/<id>,PUT /v1/fs/projects/<id>/…) | drive9 挂载命令行、API 路径 |
| kimi_chat_id | 1a014098-*---*****15cb | 聊天会话身份,随 agent-gw 凭证绑定 | /mnt/portal-overlay/.agent-gw.json(portal -agentgw 挂载) |
两者同为 1a0140…-…-8… 形态的自定义 UUID(version nibble=8,应为内部有序 ID 方案),前缀相近只是同一租户/批次生成的表象。机制上的关系是:drive9 挂载在沙箱启动时按 project-id 静态拉起(凭证在 env 文件);而 chat 身份在”claim 时”由 kimiwarden 以 bind_token(HS256 JWT)POST 到 portal :8080 换 STS 后才出现,.agent-gw.json 即此绑定的产物。一个项目工作区可被不同 chat 复用/重新绑定(portal 启动时 manifest 为空就是为这个动态绑定设计的)。
5. 结论:哪些数据持久、存在哪、怎么同步
持久(云端):
- 项目工作区全部用户数据 → drive9 server
10.213.5.144的projects/<project-id>,经 FUSE + close-sync 写回(close 即上传,shadow 本地缓存兜底,SSE 做多端缓存失效); - 用户级资产(已装 skills、plugins、CLI/plugin 凭证、vault、agent-gw 凭证)→ Kimi PortalService 云端,沙箱内以 portal FUSE 只读呈现,写入走云端控制面而非沙箱内直接写;
- 公开只读资产(websites-templates)→ KimiAPI 配置的公共只读目录。
不持久 / 只留本地:
- profile
kimi-project的[local]清单命中的路径:node_modules、.git、构建产物、缓存、.kimi、.agents、.user、.vault等 —— 明确不回传; - 容器根 overlay 的其余部分(系统改动、
/root/.cache/drive9shadow 等)随容器生命周期; /mnt/agents/.tmp(drive9 内部暂存)。
同步触发点: 文件 close(close-sync 写策略);drive9 mount drain 可手动排空;watchdog 保证 daemon 假死时被 s6 拉起重挂并重放 shadow。
凭证面(均已脱敏):
sk-kimi-8OQEd910...:agent-gw API key,存于 portal 挂载的只读.agent-gw.json;drive9_ZXlKaGJHY2l...:drive9 租户 JWT(tenant_id=890c103a-…),仅存于 root 服务 env/run/service/drive9-fuse/env,kimi 用户不可见。
6. 对 Hermes 可移植的点(详见主报告)
- “空 manifest 启动 + claim 时绑定”的 overlay 凭证注入:portal 先以无身份状态起 FUSE + HTTP bind API,由控制面(kimiwarden)下发短期 JWT 换 STS 再按需挂载 skills/插件/凭证 —— 免镜像烘凭证、天然支持会话复用与权限最小化。
- profile 驱动的同步过滤清单:drive9
kimi-projectprofile 用一份[local]glob 清单声明”哪些不回传”,把持久性策略做成显式配置而非隐式行为。 - FUSE 假死 watchdog 模式:专用小目录探活 + mkdir 自愈 + 连续失败才 pkill 交 s6 重启,避免大目录 readdir 触发回源,是远端 FS 守护的成熟做法。