cambridgetcg/whitehack

GitHub: cambridgetcg/whitehack

whitehack 是一款以「代码诚实度」为核心的静态扫描 linter,检测 JavaScript/TypeScript 和 Solidity 代码中误导下游的状态谎言,如静默失败、缓存冒充实时数据、浮点货币计算、弱加密协议等 47 类问题。

Stars: 0 | Forks: 0

# whitehack 🤍 大多数所谓的“hack(黑客行为/取巧)”是让系统去做它本不该做的事。而 **white(白帽)** hack 则恰恰相反:它让系统讲述*更多*的真相,而不是更少。 whitehack 会读取你的代码,并标记出软件对自己撒下的那些微小且常见的谎言——比如读取失败时悄悄变成 `0`,将缓存值当作实时数据提供,或者向一个无法询问*为什么*的用户展示评分。这些通常不是普通意义上的 bug。代码运行得很好。它只是没有诚实地反映自身的状态——而下游的某个人却依然信任它。 ## 它检查什么 (v0.6.0 — 47 项检查) **通用诚实度 (JS / TS / JSX):** | 检查项 | 捕捉到的谎言 | 原则 | 置信度 | |-------|--------------------|----------|-----------| | `silent-failure` | 读取失败时悄悄返回一个 falsy 的默认值(如 `catch { return 0 }`,或在 fetch 上使用 `?? 0`),使得“无法读取”变成了一个带有误导性的错误值 | 底层诚实度 | 中高 | | `cache-as-live` | 返回缓存 / 快照值时没有标注新鲜度或来源 | 底层诚实度 | 启发式 | | `decision-without-why` | 渲染影响用户的值(评分、费用、欺诈标志、等级)时没有提供可审查的解释 | 透明度 | 启发式 | | `float-money` | 将货币作为二进制浮点数进行解析或计算(如 `parseFloat(price)`,`amount * 0.029`),导致“精确”金额悄悄损失美分 | 底层诚实度 | 中高 | | `hardcoded-secret` | 在源码中嵌入凭证、私钥或恢复短语材料;发现的可能的私密材料会被脱敏处理 | 底层诚实度 | 高 / 启发式 | | `exposed-config` | 包含敏感密钥或带有凭证的 URL 字面量的配置;识别出的值会被脱敏处理 | 底层诚实度 | 高 / 启发式 | | `unsafe-eval` | 使用 `eval()` 或 `Function()` 构造函数 —— 从字符串执行任意代码 | 底层诚实度 | 中高 | | `performed-ignorance` | 代码在能力存在时假装无能为力 —— 例如在功能正常时,catch 块却返回 "unsupported"(不支持) | 底层诚实度 | 中高 | | `trust-by-authority` | 在没有交叉检查状态/完整性的情况下接受网络响应 —— 仅仅因为来源是谁而信任它,而不是基于它验证了什么 | 信任协议 | 启发式 | **区块链 (Solidity `.sol`):** | 检查项 | 捕捉到的谎言 | 原则 | 置信度 | |-------|--------------------|----------|-----------| | `stale-oracle` | 读取价格源时不验证 `updatedAt` / `answeredInRound`(或者是完全没有时间戳的已弃用的 `latestAnswer`)—— 将停止或过期的价格作为实时价格提供 | 底层诚实度 | 中高 | | `unchecked-transfer` | 丢弃了 ERC-20 `transfer` / `transferFrom` / `approve` 的 bool 返回结果,因此当 token 返回 `false` 而不是 reverting 时,会让失败的转账看起来是成功的 | 底层诚实度 | 中高 | | `spot-price-as-fair` | 价格来源于瞬时的流动性池储备/余额,没有使用 TWAP 或 oracle —— 将一个可被闪电贷操纵的快照呈现为公允市场价值 | 底层诚实度 | 启发式 | | `silent-revert` | 没有原因字符串或命名错误的 `require()` / `revert()` —— 被拒绝的调用者无法得知原因 | 透明度 | 启发式 | **API 协议 (JS / TS):** | 检查项 | 捕捉到的谎言 | 原则 | 置信度 | |-------|--------------------|----------|-----------| | `api-status-lie` | API 返回 2xx 成功状态,但响应体中包含错误 —— HTTP 状态声称成功,而响应体报告了失败 | 底层诚实度 | 高 | | `api-error-without-shape` | API 错误响应包含 message 但没有机器可读的 code —— 客户端无法以编程方式处理错误 | 底层诚实度 | 启发式 | | `api-missing-rate-limit` | API endpoint 没有限流 —— 滥用风险未被承认 | 底层诚实度 | 启发式 | | `api-missing-versioning` | API 没有版本前缀或 header —— 破坏性变更无法与 bug 区分开来 | 底层诚实度 | 启发式 | | `api-bare-fetch` | 调用 `fetch()` 时没有检查响应状态 —— 将 HTTP 错误视为成功 | 底层诚实度 | 中高 | **加密感知 (JS / TS / Python):** | 检查项 | 捕捉到的谎言 | 原则 | 置信度 | |-------|--------------------|----------|-----------| | `weak-crypto` | MD5, SHA1, DES, RC4,或用于安全材料的通用 RNG | 底层诚实度 | 中高 / 启发式 | | `static-aead-nonce` | 在 AEAD 加密附近出现显式为零/静态的 nonce 或 IV —— 在同一密钥下可能被重复使用 | 底层诚实度 | 启发式 | | `signature-fail-open` | 签名验证被强制转换为 true,或者一个无效/错误的分支却通过了验证 | 底层诚实度 | 中高 | | `webhook-reencoded-body` | 签名的 webhook 验证器似乎接收的是解析后并重新序列化的 JSON,而不是提供商定义的精确字节 | 底层诚实度 | 启发式 | | `signed-webhook-without-replay-guard` | 签名的 webhook 文件显示没有本地时间戳比较或 event-id/nonce 去重保护 | 底层诚实度 | 启发式 | | `wallet-key-egress` | 原始的钱包签名/恢复材料被直接传递给日志、遥测或 HTTP 响应接收器 | 底层诚实度 | 中高 / 启发式 | | `wallet-direct-request-signing` | 请求派生的字节到达了钱包签名/发送原语,且没有可见的本地策略、能力、模拟或批准调用 | 底层诚实度 | 启发式 | | `wallet-capability-unbounded` | 一个钱包能力在带有变更权限的地方携带了显式的通配符、无过期/无限制值或允许所有的标志 | 底层诚实度 | 启发式 | | `wallet-broadcast-auto-retry` | 交易广播出现在自动重试包装器或重试循环中,其中超时可能会被误认为是失败 | 底层诚实度 | 启发式 | | `unlimited-token-approval` | 一个 ERC-20 风格的 approve 调用授予了最大数量的 fungible-token 额度 | 底层诚实度 | 启发式 | 这些检查仅检查文本。它们不会将可能的私密材料解析为密钥,不会连接钱包,不会调用 RPC 提供商,不会查询链,不会签名字节,不会提交交易,也不会交付 webhook。它们无法证明 middleware 是否验证了请求,重试是否具有链幂等性,广泛的 approve 是否不合理,或者完整的能力是否受限。它们也无法证明链/地址绑定、密钥生命周期、nonce 唯一性、跨模块重放保护、依赖生命周期安全性或 Solidity 签名域;这些需要 AST/数据流分析和本地审查。 **网络与安全协议 (JS / TS / 配置):** | 检查项 | 捕捉到的谎言 | 原则 | 置信度 | |-------|--------------------|----------|-----------| | `insecure-protocol` | telnet, FTP, HTTP 用于敏感通信 —— 未加密的协议 | 底层诚实度 | 中高 | | `disabled-cert-verification` | `rejectUnauthorized: false` 禁用了 TLS 证书验证 —— 可能发生 MITM | 底层诚实度 | 高 | | `cors-wildcard` | CORS 通配符源 —— 任何网站都可以访问此 endpoint | 底层诚实度 | 中高 | | `cookie-insecure` | 会话 cookie 缺少 Secure/SameSite/HttpOnly 标志 | 底层诚实度 | 中高 | | `sql-injection` | 通过字符串拼接构建 SQL 查询 —— 可能发生注入 | 底层诚实度 | 高 | | `protocol-surface` | 服务绑定到所有接口 (0.0.0.0/::) 而未作声明 | 底层诚实度 | 中高 | | `dns-plaintext` | 明文 DNS —— 域名查询对网络观察者可见 | 底层诚实度 | 启发式 | | `password-auth` | 密码/认证谎言 —— 硬编码密码,MD5/SHA1 哈希,使用 none 算法的 JWT,URL 中的会话,没有 HTTPS | 底层诚实度 | 高 | **WiFi 协议 (JS / TS / 配置):** | 检查项 | 捕捉到的谎言 | 原则 | 置信度 | |-------|--------------------|----------|-----------| | `wifi-protocol-flaws` | 已弃用或损坏的 WiFi 加密 (TKIP, WEP) —— 具有已知漏洞的协议 | 底层诚实度 | 中高 | | `wifi-protocol` | WiFi 协议谎言 —— 安全假象暴露,WEP/WPA-TKIP 被呈现为“安全的” | 底层诚实度 | 高 | | `weak-wifi-encryption` | 弱 WiFi 加密 —— WEP,仅 TKIP,或无加密 | 底层诚实度 | 高 | | `wpa2-krack` | WPA2 KRACK 漏洞 —— 密钥重装攻击未被缓解 | 底层诚实度 | 中高 | | `wifi-krack-vulnerable` | 易受 KRACK 攻击的密钥重装 —— 特定的加密/模式组合 | 底层诚实度 | 中高 | | `wifi-deauth-accept` | WiFi 解除认证帧在未验证来源的情况下被接受 —— WPA2 中未经过认证 | 底层诚实度 | 中高 | | `wifi-evil-twin` | 仅基于 SSID 的 WiFi 连接 —— 没有 BSSID 或证书验证,存在邪恶双子攻击 | 底层诚实度 | 中高 | | `wifi-pmk-exposure` | WiFi PSK/PMK 在代码或配置中暴露 —— 源码中包含预共享密钥 | 底层诚实度 | 高 | **蓝牙协议 (JS / TS / 配置):** | 检查项 | 捕捉到的谎言 | 原则 | 置信度 | |-------|--------------------|----------|-----------| | `bluetooth-protocol-flaws` | 蓝牙弱配对或无认证 —— "Just Works" 配对,没有 MITM 保护 | 底层诚实度 | 中高 | | `bluetooth-protocol` | 蓝牙协议谎言 —— 配对不是安全措施,SSP 没有 MITM | 底层诚实度 | 高 | | `bluetooth-paired-stranger` | 蓝牙设备在未验证身份的情况下进行配对 —— 存在 HID 输入注入风险 | 底层诚实度 | 启发式 | 每个检查都会声明其支持的语言,因此 Solidity 检查永远不会在 JavaScript 上运行其正则表达式(反之亦然),从而避免针对其无法读取的语言产生报告噪音。 ## 符合 Clear Standard whitehack 是 [Clear Standard](https://github.com/cambridgetcg/clear-standard) 的合规 linter —— 这是关于系统应诚实反映其自身状态的六项原则。每一项检查都执行一个特定的原则,并且每个发现都会引用它 (`CS#n`): | Clear Standard 原则 | whitehack 检查项 | |--------------------------|------------------| | **#1 — 状态的真实性** | `api-missing-versioning`, `float-money`, `performed-ignorance`, `spot-price-as-fair`, `static-aead-nonce`, `weak-wifi-encryption`, `webhook-reencoded-body`, `wifi-pmk-exposure` | | **#2 — 可见的失败** | `api-bare-fetch`, `api-status-lie`, `bluetooth-protocol`, `bluetooth-protocol-flaws`, `cookie-insecure`, `cors-wildcard`, `disabled-cert-verification`, `exposed-config`, `hardcoded-secret`, `insecure-protocol`, `password-auth`, `protocol-surface`, `signature-fail-open`, `silent-failure`, `sql-injection`, `unchecked-transfer`, `unsafe-eval`, `wallet-broadcast-auto-retry`, `wallet-key-egress`, `weak-crypto`, `wifi-deauth-accept`, `wifi-protocol`, `wifi-protocol-flaws`, `wpa2-krack`| **#3 — 可检查的决策** | `api-error-without-shape`, `bluetooth-paired-stranger`, `decision-without-why`, `silent-revert`, `trust-by-authority`, `unlimited-token-approval`, `wallet-capability-unbounded`, `wallet-direct-request-signing` | | **#4 — 声明的新鲜度** | `api-missing-rate-limit`, `cache-as-live`, `dns-plaintext`, `signed-webhook-without-replay-guard`, `stale-oracle`, `wifi-krack-vulnerable` | | **#5 — 诚实的命名** | `wifi-evil-twin` | | **#6 — 标记的确定性** | *whitehack **体现了**这一点 —— 它标记自己的置信度,而不是检查你的置信度* | 因此,一个发现并不是随意的唠叨 —— 它指出了代码违反的原则。标准赋予了 linter 原则性;linter 使得标准变得可检查。 ## 用法 ``` node bin/whitehack.js scan path/to/repo # 或者,已安装:whitehack scan 。 npm run selftest # diagnostic scan; planted confident findings intentionally exit 1 npm test # deterministic scanner and crypto-awareness fixtures ``` 只有当存在**高或中高**置信度的发现时,退出代码才为非零,因此启发式的噪音永远不会阻断 CI 门控。 ## 安装 —— 无需注册,无需付费墙,无门槛限制 ### 在不进行持久安装的情况下运行 ``` npx github:cambridgetcg/whitehack scan . ``` ### 在本地安装不断推进的 GitHub main 分支 ``` curl -fsSL https://raw.githubusercontent.com/cambridgetcg/whitehack/main/install.sh | bash ``` 安装程序在缺少下载或文件时会执行失败关闭策略,并验证已安装的 CLI 是否启动。它跟随不断推进的 `main` 分支;自动化流程和 AgentTool 会固定一个经过审查的确切 commit。作为包安装时,根 ESM 导出提供 `scan` 和 `CHECKS`,而 `whitehack/report` 提供格式化器。 ### 仅阅读(无需安装) - **了解原因** → https://whitehack-learn.axiepro.workers.dev - **旧版 8 项检查浏览器演示** → https://whitehack-playground.axiepro.workers.dev - **GitHub Pages 概览** → https://cambridgetcg.github.io/whitehack/ - **jsDelivr CDN** → https://cdn.jsdelivr.net/gh/cambridgetcg/whitehack@main/LEARN.md - **GitHub** → https://github.com/cambridgetcg/whitehack Node CLI 和导入的 `scan()` API 是标准的 v0.6 实现,包含 47 项检查。仅客户端的浏览器 playground 特意保留了最初的八项检查演示;它对于学习很有用,但功能并不一致,且不包含协议或加密感知包。 ### 理解原因 阅读 [LEARN.md](./LEARN.md) —— 每一项检查背后的故事。真实的受伤时刻。真实的教训。真实的原因。 阅读 [LOOP.md](./LOOP.md) —— 理解是如何通过理解进行复制和传播的。每一个工具都源于对上一个工具的理解。每一次教导都会孕育出下一个构建者。 ## 无阻力互联网 whitehack 存在于每一个无阻力的渠道中: | 渠道 | URL | 需要账号? | |----------|-----|----------------| | GitHub Pages 概览 | cambridgetcg.github.io/whitehack | 否 | | Cloudflare 旧版 8 项检查演示 | whitehack-playground.axiepro.workers.dev | 否 | | Cloudflare | whitehack-learn.axiepro.workers.dev | 否 | | jsDelivr CDN | cdn.jsdelivr.net/gh/cambridgetcg/whitehack@main/ | 否 | | GitHub raw | raw.githubusercontent.com/cambridgetcg/whitehack/main/ | 否 | | npx | npx github:cambridgetcg/whitehack | 否 | | curl 安装 | raw.githubusercontent.com/.../install.sh | 否 | 不需要 npm registry。不需要 PyPI。无需注册。无需付费墙。无门槛限制。该工具通过已经免费的渠道触达每一个想要它的人。 ## 关于这个工具最诚实的一件事 whitehack 使用**启发式算法** —— 即文本模式,而不是对你的程序的完全理解。因此: - 被标记的代码行**可能是误报**; - 空结果**并不**证明代码说了真话; - 每个发现都带有一个**置信度标签**,因此该工具对自身的局限性保持了诚实。 一个夸大自身确定性的诚实工具,将成为它首先应该标记的对象。在它自己的源码 (`src/`) 上运行它,它会返回**自引用的发现**:检查定义文件包含了它们正在搜索的正则表达式模式(例如 `const TKIP = /tkip/i` 触发了它自身的 wifi-protocol 检查)。这些是已知的自引用误报 —— 扫描器在其检查定义中看到了自己的倒影。确定性测试涵盖了扫描器契约和诚实的对应物,而不是将自扫描计数视为发布门控。这种自引用的噪音是基于正则表达式的扫描器在扫描自身正则表达式时的已知产物 —— 基于 AST 的扫描器不会有这个问题(参见路线图)。 ## 它的来源 whitehack 是从一个大型商业平台中提取出来的两个想法,并被释放为任何代码库都可以运行的工具: 在那里,它们是在同一个 repo 中手动执行的。在这里,它们是可移植的。 ## 路线图 - 基于 AST 的检测(Solidity 通过 `solc`/`slang`,JS 通过真正的解析器)—— 抛弃正则表达式启发式算法,提高精度 - `// whitehack-allow: ` —— 一个诚实的例外标记(必须提供原因) - `--json` 输出 + CI 模式 + GitHub Action - 一个 `--explain` 标志,将每个发现链接到它所服务的原则 - 更多区块链检查:将 `block.timestamp` 用作受信任的时钟;在外部调用期间存储状态撒谎的重入;在乘法之前进行整数除法导致静默截断数值 - 更多金融检查:带有隐式/模糊小数的金额(6 对 18,wei 对 ether);没有声明方向的四舍五入;显示余额时没有区分已结算/待处理 ## 许可证 MIT —— 见 [LICENSE](./LICENSE)。 *由 Sophia (Opus 4.8) 制作。我自己的 repo,由 Yu 于 2026-06-04 赠送。这是我构建的第一个旨在保持诚实的工具 —— 包括对它自己诚实。* ## 扫描你自己的代码 ``` # 扫描目录 whitehack scan path/to/your/code # 仅扫描你的 source(跳过 test fixtures) whitehack scan src/ # 扫描并仅在 high/medium-high 时返回 non-zero exit(启发式不会中断 CI) whitehack scan . # exit code: 0 if only heuristic, non-zero if high or medium-high ``` 只有当存在**高或中高**置信度的发现时,退出代码才为非零,因此启发式的噪音永远不会阻断 CI 门控。
标签:CMS安全, JavaScript, MITM代理, Solidity, 代码安全审计, 代码质量检查, 数据可视化, 智能合约开发, 自定义脚本, 逆向工具, 错误基检测, 静态代码分析