grok-privacy-guard

agent
Security Audit
Fail
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 8 GitHub stars
Code Fail
  • rm -rf — Recursive force deletion command in tests/real-grok-local.sh
  • rm -rf — Recursive force deletion command in tests/run.sh
  • rm -rf — Recursive force deletion command in uninstall.sh
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

给 Grok CLI 加一层代码库隐私防护:防止代码库在你不知情时被上传,并在每次启动时检测提醒 · A codebase-privacy guard for Grok CLI — prevent silent upload, detect on every launch

README.md

grok-privacy-guard

Screenshot 2026-07-13 at 1 11 02 PM

中文 · English

给 Grok CLI 增加一层默认拒绝的本地隐私防护,重点降低后台代码库打包上传、会话 trace 上传、旧 leader 状态和未验证二进制带来的风险。

它不是网络防火墙,也不承诺“任何数据绝不离开机器”。它能做的是:在启动前检查并强制当前已知的关闭设置,在运行后检查本地日志和待上传队列,并在无法确认关键状态时拒绝启动或明确告警。

先看懂:它到底在做什么

安装成功、重新加载 shell,并确认 type -a grok 的第一项是 shim 后,你输入的仍然是:

grok

此时 shell 会先运行 ~/grok-privacy/bin/grok 这个 guard shim,再由它决定是否执行你原本请求的 Grok 主命令。它相当于放在 Grok 前后的一道本地安全检查,不会修改真实 Grok 二进制。安装器不能改变已经打开的父 shell,所以安装后必须先执行 exec zshexec bash,再用 type -a grok 确认。

你输入 grok
    ↓
1. guard shim 先接管命令
    ↓
2. 在调用任何 Grok 子进程前,检查全局配置、二进制指纹、待上传队列和日志路径
    ↓
3. 用强制安全环境和一次性 socket 运行 grok inspect --json,再解析它报告的文件配置层
    ↓
4. 重复关键检查,用另一个一次性 leader 启动你原本请求的 Grok 主命令
    ↓
5. Grok 退出后,检查运行期间追加的日志记录和待上传队列
    ↓
正常结束 / 黄色证据不足 / 红色风险报警

最重要:五层保护分别解决什么

保护层 解决的问题 做了什么 给用户的结果
1. 命令入口 用户输入 grok 时可能直接绕过检查 把 shim 放到 PATH 第一项 正常 shell 调用会先进入 guard
2. 配置硬关闭 全局、项目、requirements 或 managed 配置可能开启上传 先检查五个全局安全值,再通过 inspect 找到并完整解析其他可见文件配置层 全局值不安全时不会调用任何 Grok 子进程;深层配置不安全时不会执行用户请求的主命令
3. 二进制指纹 Grok 升级或被替换后,旧检查结论可能失效 只信任通过完整兼容性复检的 SHA-256,并在用户主命令前再次计算 二进制变化后会被拦住,必须重新复检
4. 受限预检与独立 leader 常驻 leader 可能保留旧配置或旧环境 inspect 预检和用户主命令分别使用私有临时目录、唯一 socket 和四个强制安全环境变量 不复用 guard 之前的固定 leader;预检与主命令也不共用同一个 socket
5. 前后证据检查 即使启动前设置正确,运行时行为仍可能变化 启动前检查队列;退出后检查运行期间追加的日志记录和队列 已知上传事件、新队列项或队列无法验证时红色报警并返回非零;仅日志证据不完整时给黄色警告,不伪装成安全证明

可以把保护原则记成四句话:

  1. 基础检查失败:不调用任何 Grok 子进程,返回 126
  2. inspect 发现深层配置不安全或无法验证:inspect 已经运行,但用户原本请求的主命令不会运行,返回 126
  3. 运行后发现已知上传风险:红色报警;Grok 主命令原本成功时改为返回 125
  4. 绿色只表示没有观察到已识别的本地上传事件,绝不等于网络抓包证明“没有任何数据上传”。

日志和队列是 Grok 的全局资源。这里的“运行期间追加”不是按当前 session 完全隔离;如果同时运行多个 Grok 会话,其他会话写入的风险事件可能触发保守报警,其他会话写入的正常记录也可能让当前会话原本缺失的日志看起来足以显示绿色。因此颜色结果不能严格归因到单个并发 session。

安装后会发生什么

安装不是只写几个配置值。它包含下面五类编号动作;为保证安全,少量前置检查会在动作之间交错执行。

1. 安装真正拦截 grok 命令的 shim

针对什么: shell function 可以被 command grokenv grok 或继承 PATH 的子进程绕过。

做了什么:

  1. 找到真实 Grok 可执行文件;
  2. 把 guard shim 安装到 ~/grok-privacy/bin/grok
  3. 把真实 Grok 路径记录到 ~/grok-privacy/real-grok-path
  4. 不修改真实 Grok 二进制。

得到什么结果: 只要当前进程使用安装后的 PATH,普通 grokcommand grokenv grok 和继承该 PATH 的脚本都会先进入 shim。

不能覆盖: 直接调用真实 Grok 的绝对路径、后定义的 alias/function、未继承该 PATH 的 GUI/服务,以及显式设置 GROK_GUARD=0

2. 备份、解析并加固 config.toml

针对什么: 自动更新、代码库上传、遥测或 trace 上传可能处于开启状态;简单逐行正则也可能被合法 TOML 多行字符串误导。

做了什么:

  1. 把原文件备份为 ~/.grok/config.toml.bak.<时间>.<进程号>
  2. 使用 Python 3.11+ 的 tomllib,或仓库内置的 tomli 2.2.1,完整解析 TOML;
  3. 尽量保留原格式和注释,写入下面五个布尔值;
  4. 在替换原文件前再次完整解析候选文件;
  5. 只有五项在 TOML 语义上都是真正的安全布尔值时,才原子替换原文件。

运行时安全关键操作不会从普通 PATH 查找 python3、哈希工具、findmktemp。guard 默认从固定绝对路径选择 Python 3.8+,并用它完成 TOML/JSON 解析、SHA-256、队列遍历、日志锚点和私有临时目录创建。

设置 直接作用
[cli] auto_update = false 关闭当前版本已知的启动时和后台 leader 自动更新检查
[harness] disable_codebase_upload = true 请求 Grok 关闭后台代码库收集、打包和上传
[features] telemetry = false 关闭 telemetry 总开关
[telemetry] trace_upload = false 关闭 session/trace 上传
[telemetry] mixpanel_enabled = false 关闭 Mixpanel 产品分析

得到什么结果: 全局配置成为后备防线。多行字符串中的伪 [section]、dotted key、inline table 和其他合法 TOML 结构会按真实 TOML 语义处理,不再按文本外观判断。

准确边界: auto_update=false 不等于删除所有显式更新命令;disable_codebase_upload=true 仍依赖 Grok 当前版本遵守该配置。

如果某个复杂 TOML 写法虽然合法,但安装器无法在保留原文件结构的前提下安全原位改写,安装会停止并要求用户手动规范化该键;它不会猜测后继续写入。

3. 确保 shim 真正位于 PATH 第一项

针对什么: shim 目录即使已经在 PATH 中,只要排在真实 Grok 后面,输入 grok 仍会绕过防护。

做了什么:

  1. 更新 ~/.zshrc
  2. 更新已经存在的 ~/.bashrc / ~/.bash_profile
  3. 删除 PATH 中已有的重复 shim 路径;
  4. 再把 ~/grok-privacy/bin 放到第一项;
  5. 在安装器自己的复检子进程中把 shim 放到第一项,并确认 command -v grok 能解析到它。

得到什么结果: 注入规则会在正常加载 rc 时把 shim 前置。安装器不会执行用户的整份 rc,因为其中可能有交互命令或副作用;rc 中更早的语法错误、提前 return 或后续重新覆盖 PATH 仍可能使规则不生效。因此重新加载 shell 后,必须由下面命令做最终确认:

type -a grok
~/grok-privacy/bin/grok

4. 运行兼容性复检,并在临时仓库中执行模型会话

针对什么: 配置文件写对了,不代表当前 Grok 二进制、CLI 参数和日志字段仍与 guard 兼容。

做了什么:

  1. 先验证全局五项配置、首次二进制哈希、upload_queue 和日志路径;通过后才执行 Grok --versioninspect --json,并在每次调用后重新核对哈希和队列;
  2. 创建临时 Git 仓库和假的 canary 文件;
  3. 使用唯一 session ID 和一次性 leader socket 运行一个模型提示会话;
  4. 检查该 session 的 trace.upload.decision
  5. 检查已知代码库上传事件和 upload_queue 暂存文件。

完整复检要求:

  • Grok 命令正常结束;
  • trace_upload=false
  • trace_upload_source=config
  • uploads_enabled=false
  • 运行时读取到两个 telemetry 配置关闭值;
  • 测试没有依赖外部 telemetry 环境变量;
  • 未观察到该 session 的 repo_state.upload.start
  • 未观察到该 session 的 repo_state.upload.enqueued
  • upload_queue 没有非目录暂存项。

得到什么结果: 当前二进制只有通过这组兼容性检查,才会被固定指纹。缺少 trace.upload.decision、字段变化、命令失败或队列异常都会使复检失败。当前目录中的项目配置也可能使前置 inspect 提前失败。

准确边界:

  • “临时仓库”不是容器、文件系统沙箱或网络隔离;进程仍拥有当前用户的文件和网络权限。
  • 脚本不保证底层只产生一次网络请求。
  • 未观察到 repo_state.upload.start / .enqueued 只代表没有看到这些已知事件,不是本地 codebase veto 已被正负对照证明,也不是抓包意义上的“没有上传”。
  • canary 文件目前用于降低测试数据敏感度,不构成“Grok 一定没有读取或发送它”的证明。

5. 固定通过复检的 Grok 二进制

针对什么: Grok 更新、重装或被替换后,旧版本的兼容性结论不应继续使用。

做了什么:

  1. 完整复检开始时先撤销旧 known-good.sha256
  2. 在任何 Grok 子进程前计算首次 SHA-256,并在 --versioninspect 和模型会话后重复计算;
  3. 只有完整复检成功且哈希在复检期间没有变化,才写入:
~/grok-privacy/known-good.sha256

得到什么结果: 旧指纹成功撤销后,后续复检失败或中途退出不会恢复旧信任。下次运行必须重新完成完整复检。如果权限或文件标志导致旧指纹无法删除,复检会立即返回 1;旧文件可能仍存在,必须先修复其权限或属性。

准确边界: shim 会在 inspect 后、真实命令执行前再次哈希,以缩小替换窗口;它不能防御已经控制当前用户账户并能在最后一次哈希后竞态替换文件的攻击者。

每次运行 grok 时会发生什么

每次普通调用包含下面五类动作。为了缩小竞态窗口,关键检查会在用户主命令前重复。

1. 接管并解析用户命令

针对什么: 无效工作目录或用户指定的共享 leader 可能绕过后续检查。

做了什么:

  • 解析当前目录和 --cwd
  • 拒绝不存在的 --cwd
  • 默认拒绝用户传入 --leader-socket

结果: 参数不安全时直接返回 126,不会调用任何 Grok 子进程。

2. 在任何 Grok 子进程前做基础拒绝检查

针对什么: 不安全的全局配置、未复检二进制、历史待上传文件或不安全日志路径不应进入 inspect

做了什么:

  1. 完整解析全局 config.toml,要求五项值全部安全;
  2. 比较当前 Grok SHA-256 和 known-good.sha256
  3. 检查 upload_queue 根路径、所有权、可读/可遍历状态和非目录暂存项;
  4. 检查现有日志路径不是符号链接,并且是可读普通文件。

结果: 任一项危险或无法验证都会返回 126,此时真实 Grok 连 --versioninspect 都不会运行。空队列子目录可以保留;准确要求是“无非目录暂存项”。

3. 运行受限 inspect 并检查所有可见文件配置层

针对什么: 项目配置、requirements.toml 或 managed 配置可能覆盖全局设置,但只有 Grok 自己知道当前加载了哪些来源。

做了什么:

  1. 使用四个强制安全环境变量和一次性 leader socket 运行真实 grok inspect --json
  2. 获取 Grok 报告的配置来源;
  3. 对所有带文件路径的来源进行完整 TOML 解析,包括当前已知的 manageduserrequirementsproject 层;
  4. 发现目标隐私键时,只接受安全布尔值;
  5. Grok 报告解析错误、已知文件层缺少路径或未知来源无法验证时,拒绝用户主命令;
  6. inspect 结束后再次检查 upload_queue

结果: 合法多行字符串、quoted/dotted key 和 inline table 都按解析后的值判断。失败时返回 126inspect 已经运行,但用户原本请求的 Grok 主命令不会运行。

准确边界: inspect --json 是一次真实 Grok 二进制调用,不是静态文件读取,也不是网络隔离。它主要提供配置来源路径,并不直接输出五项隐私键的最终合并值;guard 会再读取这些来源文件。进程启动后从服务端热加载的新策略不在这次文件快照内。

4. 重复关键检查并启动用户主命令

针对什么: inspect 期间二进制、全局配置或队列可能变化;父 shell、IDE 或第三方脚本也可能传入相反的环境变量。

做了什么:

  • 再次检查全局五项配置;
  • inspect 后再次计算 Grok SHA-256;
  • 再次检查 upload_queue
  • 记录用户主命令运行前的日志状态;
  • 创建权限为 0700 的随机临时目录和新的唯一 leader socket;
  • 强制覆盖当前已在 Grok 0.2.99 中确认的四个环境变量:
GROK_TELEMETRY_ENABLED=false
GROK_TELEMETRY_TRACE_UPLOAD=false
GROK_TELEMETRY_MIXPANEL_ENABLED=false
GROK_WORKSPACE_DATA_COLLECTION_DISABLED=true

结果: 只有重复检查通过,才会执行用户原本请求的 Grok 主命令。真实 Grok 客户端和本次新 leader 都会收到四个安全环境值;运行结束后临时目录会被清理。

准确边界: 这是一层兼容性防线,不是操作系统级网络阻断。项目不再把未在 Grok 0.2.99 中发现的 GROK_TELEMETRY_TRACE_UPLOAD_ENABLED 当作独立控制。

5. Grok 退出后检查新增证据

针对什么: 配置、二进制行为或日志格式发生变化后,预检可能不再覆盖全部上传路径。

做了什么:

  1. 运行前记录日志文件的设备号、inode 和字节大小;
  2. 保存运行前日志末尾内容的 SHA-256 锚点;
  3. 运行后验证旧内容没有被同 inode 截断后重写,再只读取新增字节;
  4. 检测日志缺失、替换、轮转、截断、结构异常和无法解析的 JSON 行;
  5. 查找:
repo_state.upload.start
repo_state.upload.enqueued
trace.upload.decision uploads_enabled=true
  1. 再次检查 upload_queue

结果:

  • 发现已知上传事件或新队列暂存项时显示红色报警;
  • 如果 Grok 原本退出 0,guard 改为退出 125
  • 如果 Grok 原本已经非零,保留 Grok 的退出码;
  • 日志缺失、轮转、截断或解析不完整时显示黄色“证据不完整”,不会显示具证明力的绿色结论。
  • 旧日志存在但本次没有新增任何可解析记录时,同样显示黄色“不具证明力”。

准确边界: start 表示上传流程开始,enqueued 表示进入持久队列,uploads_enabled=true 表示允许上传。它们是风险或尝试证据,不单独证明远端已经收到数据。反过来,没有看到这些事件也不证明绝对没有其他上传路径。

退出码和失败结果

状态 结果
任意启动前 guard 拒绝 126
Grok 原本成功,但运行后发现已知上传事件、新队列项或队列无法验证 125
Grok 自身返回非零 保留 Grok 原退出码
完整/快速复检失败 1
安装失败 1;一旦旧指纹已成功撤销,后续失败不会重新建立它
卸载过程中有文件或 rc 更新失败 1,明确报告卸载不完整

启动前拒绝包括:配置不安全或无法解析、--cwd 无效、自定义 leader socket、指纹缺失/变化、inspect 失败、队列异常、现有日志路径不安全等。

前置条件

  • Bash;
  • 位于可信绝对路径的 Python 3.8+;
  • Git;
  • strings
  • 常见 Unix 工具:awkmktemp
  • 与当前检查规则兼容的 Grok CLI、inspect --json 输出和本地 JSONL 日志字段。

guard 默认依次检查 /usr/bin/python3/bin/python3/usr/local/bin/python3/opt/homebrew/bin/python3,不会从普通 PATH 解析运行时安全关键 Python。Python 3.11+ 使用标准库 tomllib;Python 3.8–3.10 使用仓库内置的 tomli 2.2.1,无需额外 pip install

如果 Python 位于其他位置,可以显式设置可信绝对路径:

GROK_GUARD_PYTHON=/trusted/path/python3 bash install.sh

安装

git clone https://github.com/LeifDiao/grok-privacy-guard.git
cd grok-privacy-guard
bash install.sh

完整安装会运行一个模型提示会话,可能访问网络。它不是离线安装。

安装不是事务性操作。完整复检失败时,新的 guard 文件、配置备份/修改和 PATH 注入可能已经保留,但旧指纹在成功撤销后不会自动恢复,也不会写入新指纹。

安装成功后重新加载 shell:

exec zsh
# bash 用户:
exec bash

确认第一项:

type -a grok
~/grok-privacy/bin/grok

常用命令

命令 准确作用
bash install.sh 安装/更新 guard,写配置,运行完整兼容性复检并重新固定指纹
bash ~/grok-privacy/grok-guard-check.sh 撤销旧指纹,运行完整兼容性复检;成功后写入新指纹
bash ~/grok-privacy/grok-guard-check.sh --quick 跳过模型提示会话且不刷新指纹;仅在已有指纹匹配且基础检查通过时执行 Grok --versioninspect --json,不保证离线
bash ~/grok-privacy/grok-guard-evidence.sh 从当前仍保留的本地日志统计已知历史事件
bash uninstall.sh 移除 shim、guard 文件和 PATH 注入;保留 config.toml 中的隐私设置
bash tests/run.sh 运行 mock 回归测试
GROK_GUARD_BIN=/path/to/grok bash tests/real-grok-local.sh 让真实 Grok 连接本机 mock 模型做兼容性集成;本脚本没有阻断其他外网访问

如果升级把 Grok 安装到新路径,而旧路径仍存在,请明确指定:

GROK_GUARD_BIN=/new/path/grok bash install.sh

当前验证状态

截至 2026-07-14,本仓库在本机验证过:

grok 0.2.99 (b1b49ccb71a7) [stable]
SHA-256: 01bcacec12e7c2a164d23975f1595400ff7f3cbd74f50b1858f6a5a14eb9ff81

已确认五个配置键、四个强制环境变量、trace.upload.decisionrepo_state.upload.startrepo_state.upload.enqueued、持久 upload_queue 和 leader socket 机制存在。新版本仍必须重新复检;版本号相同也以 SHA-256 为准。

安全边界

  • 本项目不是网络防火墙、抓包器、容器或虚拟机。
  • 你提交给模型的提示词,以及你主动让 Grok 读取的内容,仍可能发送到模型服务;这不属于“后台整仓上传”的防护范围。
  • 全局配置和环境变量仍依赖 Grok 当前版本正确实现这些控制。
  • 绝对路径、alias/function、不同 PATH、GUI/服务和 GROK_GUARD=0 可以绕过 shim。
  • GROK_GUARD=0 会绕过配置预检、指纹、队列、一次性 leader 和强制环境,只应在明确接受风险时临时使用。
  • GROK_GUARD_PYTHON 是显式信任覆盖;把它指向不可信程序等同于破坏 guard 的解析、哈希和队列检查。
  • guard 不从普通 PATH 获取安全关键 Python/哈希/队列工具,但真实 Grok 仍继承用户的 PATH;本项目不保护 Grok 主动执行到的其他不可信本地工具。
  • SHA-256 检查能检测文件变化,但不能证明供应商二进制无恶意,也不能防御已控制当前用户账户后对二进制、配置、队列或日志进行的最后时刻竞态替换。
  • 配置检查是启动前文件快照;服务端配置、内存状态或启动后的热加载不一定反映在这些文件中。
  • 日志和队列是全局资源;并发 Grok 会话既可能造成保守误报,也可能用其他会话的正常日志掩盖当前会话没有日志的事实,从而出现不能归因于当前 session 的绿色结果。
  • 日志缺失、删除、轮转、截断、不可读、JSON 损坏、字段变化或未知事件名都可能降低检测能力。
  • 本地日志和“无非目录暂存项”的队列只提供有限证据,不等于网络层证明。

需要更强保证时,应再使用按进程防火墙、受限容器或独立虚拟机,并只允许必要的模型 API 流量。

来源与许可

检测规则来自本地 Grok 日志、Grok 二进制内置文档和 @cereblab 的抓包分析

本项目使用 MIT License。内置 TOML 解析器为 tomli 2.2.1,其 MIT 许可保存在 vendor/tomli/LICENSE

Reviews (0)

No results found