跳到主要内容

安全评审

发布之前,BitTool Signer 1.0.0 的源代码在每个平台上都接受了两次 AI 辅助的安全评审,各次评审分别单独进行。四份报告均在下方全文公开。没有一次发现严重或高危问题。iPhone 版的两次评审各发现一项低危问题;Android 版的评审发现了中危问题,其中有四项中危级别的发现在已发布的 Android 1.0.0 中尚未解决,而且其中三项位于两款 App 共用的签名引擎中。

请先了解这些局限
  • 这些都不是安全公司进行的审计,也都没有人类审计员参与。
  • Opus 5 和 Opus 5.5 评审出自同一模型家族,被评审代码中相当一部分也由它编写或修改。报告指出,不得将其作为第三方证明或认证。
  • GPT-6 Astra 的评审说明,它们是为项目所有者编写的 AI 辅助工程评审,而不是审计机构出具的认证,也不是人工签字确认。
  • 两份 Android 报告都建议,在用这款 App 保护大额资产之前,先修复尚未解决的中危发现。 BitTool Signer Android 1.0.0 发布时这些问题仍未解决;参见全部发现。
  • 独立的第三方审计尚未进行。 报告将它与真机测试、使用真实第三方钱包的往返测试一起,列为存放大额资金之前仍需完成的工作。

BitTool Signer iPhone 版​

两份报告​

Opus 5GPT-6 Astra
日期2026 年 10 月 19 日2026 年 10 月 18 日(报告 BTS-SEC-2026-1018-R3)
评审的代码标签 v1.0.0,提交 f62137210 月 18 日的工作树:提交 3d706b7,外加 59 个已修改的文件和一个新增测试
评审的引擎(signer.js,SHA-256)6933d0d8…f210776933d0d8…f21077
方法逐行源码评审(3,546 行 JavaScript、11,858 行 Swift)、11 项攻击探测、针对二维码输入的 4,000 例变异测试、测试套件、净室重建按子系统进行源码评审、与上一轮评审对比、独立的 Bitcoin 和 Solana 测试数据、1,509 例变异测试、测试套件、可重现构建、依赖项安全公告
运行的测试210 项引擎测试、168 项原生测试210 项引擎测试、177 项原生与 UI 测试
结果严重 0 · 高 0 · 中 0 · 低 1 · 信息 3严重 0 · 高 0 · 中 0 · 低 1 · 观察项 4
独立性由编写了很大一部分代码的作者进行的自我评审AI 辅助,为项目所有者编写

两次评审检查的是同一个引擎文件,也就是 BitTool Signer 1.0.0 随附发布的那个文件:所有交易解析器、风险规则和签名计划都在其中。App 的其余部分(界面、钥匙串、存储)则通过阅读 Swift 源码进行评审。

全部发现​

ID严重程度发现在 1.0.0 中的状态
BTS-OP5-01低高风险确认仅在界面中强制执行。对于部分解码和不透明的请求,引擎要求用户明确确认;但对于完全解码的高风险请求(无限额授权、setApprovalForAll、Safe 权限变更、代币销毁),引擎并不要求。App 在勾选确认框之前会禁用“签名”按钮,因此在 1.0.0 中攻击者无法触及这一问题;它之所以重要,是因为引擎是用户可以通过哈希验证的部分。未解决。报告建议在 1.0.1 中将该检查加入引擎。
R3-01低带找零的销毁交易的 Bitcoin 摘要。对于包含金额非零的 OP_RETURN 输出、且有已验证找零的交易,结果页面和活动记录中的简短摘要显示为“Every output returns to your wallet”(所有输出都回到你的钱包)。签名界面本身会正确显示销毁、其金额以及高风险。未解决(1.0.0 随附的引擎就是被评审的版本)。
BTS-OP5-02信息活动记录中的一个本地化键由引擎输出拼接而成,而 SwiftUI 会将其按 Markdown 渲染。它目前可能取到的每个值都是固定标签,因此这是一个潜在问题。未解决,潜在。
BTS-OP5-03信息保险库的密码 KDF(PBKDF2-HMAC-SHA256,600,000 轮)不是内存困难型算法。第二层加密使用与设备绑定的钥匙串密钥,缓解了这一问题:仅凭复制出去的保险库文件,甚至无法发起攻击。已接受;建议在未来的保险库格式中采用 Argon2id。
BTS-OP5-04信息Solana 派生过程中的中间 Ed25519 密钥材料没有被显式擦除;真正起作用的控制措施是销毁 JavaScript 上下文。未解决,固有局限。
O-01信息导入时,一次较慢的“该钱包是否已存在?”查询可能在助记词被编辑之后才完成,并为之前的那个钱包提供密码重置。重置操作本身会重新派生钱包身份,并拒绝错误的钱包;保险库不会发生任何变化。报告撰写时尚未解决。
O-02信息Safe 和 Solana 的摘要来自范围受限的解码器,而不是来自执行交易。离线状态下无法得知合约的实时状态。设计如此;已在审核界面中披露。
O-03信息在 Swift 和 JavaScript 中无法保证内存被完全清零;物理设备、操作系统随机数生成器以及分发的二进制文件均未经测试。局限。
O-04信息六条仅涉及开发依赖的安全公告(3 条中等级别、3 条低级别)。受影响的包不在随附发布的引擎中。维护事项。

两份报告还复测了此前两轮评审的发现,包括一项高级别问题(含 DELEGATECALL 和嵌套 MultiSend 的 Safe 多签交易的摘要),以及 Bitcoin 手续费摘要和 Solana 销毁摘要中的若干低级别问题,确认它们均已修复。Opus 5 还指出,TRON 签名不携带网络标识符,这是 TRON 协议本身的特性而非缺陷;App 已披露这一点。

之后在共用引擎中发现的问题​

BitTool Signer iPhone 1.0.0 随附的引擎 SHA-256 为 6933d0d8…f21077。GPT-6 Astra 对 Android 版的评审正是针对这个文件复现了引擎方面的发现,而 Opus 5.5 发现所涉及的 Bitcoin、EVM 和 TRON 代码在该文件中也完全相同。因此,这些引擎方面的发现同样适用于 iPhone 1.0.0:

ID严重程度对 iPhone 1.0.0 的影响
BTS-02、BTS-07中与一笔极小转账一起发送的 Solana 销毁、权限变更或授权委托,会被摘要显示为那笔转账。详情中的警告和风险确认仍然保留。
BTS-08中钱包单签配置下任意地址索引的比特币找零都会被接受,包括观察钱包永远不会扫描到的索引。
BTS-09低至中对于未知的 EVM 或 TRON 合约调用,保存的摘要不包含随调用发送的原生币。审核卡片会显示它。

上文的 R3-01 与 Android 的 BTS-04 是同一缺陷,Android 版引擎已将其修复。Opus 5.5 报告建议在共用引擎中修复其余问题,修复随后会同时进入两款 App。

评审确认了什么​

领域已确认详情
签名在 Release 构建中,签名的唯一途径是通过一个固定的计划。六项相互独立的检查将签名与审核过的请求、计划中的钱包以及经批准的密钥绑定在一起,并且引擎在签名前会从解密后的种子重新派生所有内容。已通过实际运行确认。签名前的检查
随机性助记词来自 SecRandomCopyBytes;出错时创建过程终止,不存在回退。引擎的 crypto.getRandomValues 和 Math.random 被桥接到同一来源。种子生成
密钥存储两层带认证头部的 AES-GCM、仅限本设备的钥匙串密钥,以及重启后依然有效的失败尝试限速。密钥存储
拒绝本文档描述的每一种拒绝都成立:SIGHASH_NONE/SINGLE/ANYONECANPAY、缺少前序交易的 SegWit v0 输入、Solana 地址查找表、EIP-7702、blob 交易、原始哈希 eth_sign 以及不支持的链 ID。限制与错误
不可信输入两次评审共计 5,509 个经过变异的二维码、CBOR、PSBT 和 JSON 输入:无效输入无一被接受,也没有出现未受控的异常。UR 与 CBOR
离线既未链接 CFNetwork,也未链接 Network.framework,JavaScript 桥接也不暴露任何网络 API。安全模型
供应链引擎可以从标签逐字节重建;运行时依赖都锁定了确切版本;生产依赖审计未报告任何漏洞。见下文

评审未覆盖的内容​

未覆盖的内容包括:物理设备上的测试(故障注入、内存转储、侧信道)、操作系统随机数生成器和 Secure Enclave 的内部机制、引擎文件之外的 App Store 二进制文件来源、真实区块链上的交易、与第三方钱包的往返测试、对密码学依赖的完整审计、21 种界面语言的语言审校,以及形式化验证。测试套件通过,只覆盖它所测试的用例,而不是所有交易或设备。

自行验证引擎​

App Store 中的可执行文件无法逐字节重现(Apple 会对其重新签名并加密),但引擎是一个未加密的资源文件,可以进行比对。从标签构建它:

git clone https://github.com/bitbill/bittool-signer-ios
cd bittool-signer-ios && git checkout v1.0.0
cd engine && npm ci --ignore-scripts && npm run build
shasum -a 256 ../BitToolSigner/Resources/signer.js
# 6933d0d8a6f60faa8222506ac0bd7eef80eb884c9f73e31e9f354b4740f21077 (1,181,026 bytes)

然后将它与你所安装 App 中的文件进行比较:使用 Apple Configurator 将 App 下载为 .ipa,解压后计算 Payload/BitToolSigner.app/signer.js 的哈希。完整步骤(包括验证在哪一步止步)见代码仓库中的 Reproducible-Build.md。

BitTool Signer Android 版​

两份报告​

Opus 5.5GPT-6 Astra
日期2026 年 10 月 25 日2026 年 10 月 24 日
评审的代码正式版 1.0.0(版本号 1000001):代码提交 71af693,发布记录 62996b8发布之前的提交 e7e71fb:针对上一基线 bb1e656 之后改动的复审
评审的引擎(signer.js,SHA-256)4b371759…00fa196933d0d8…f21077,即 iPhone 1.0.0 随附的引擎
方法分五个领域进行源码评审,每个领域都端到端追踪;每项发现都对照代码复核;用合成数据复现引擎问题;检查依赖项和构建产物评审改动的代码及其调用方,验证三项修复,针对已提交的引擎包复现问题,运行自动化回归检查
运行的测试2,075 项 App 测试、217 项引擎测试,发布验证脚本 25 项全部通过1,616 项 Android 测试;210 项引擎测试,其中一项失败、一项未实际运行就显示通过(BTS-06)
结果严重 0 · 高 0 · 中 4(其中一项评为低至中)· 低 9 · 若干信息性说明严重 0 · 高 0 · 未解决:中 1、低 1、验证类 1 · 已解决 3
建议在面向保护大额钱包的正式发布之前,修复 BTS-07、BTS-08 和 BTS-10在该版本下,暂缓面向大额钱包的正式发布
独立性被评审代码中很大一部分出自同一模型家族AI 辅助;未修改生产代码

两次评审都覆盖了整个 Android App:Kotlin 模块、原生宿主(基于 QuickJS 的 JNI 层及原生 PBKDF2),以及与 iPhone 版共用的签名引擎。

全部发现​

Opus 5.5 评审的就是正式发布的代码,因此以下是 BitTool Signer Android 1.0.0 的发现。

ID严重程度发现所在位置
BTS-07中Solana 权限变更可以隐藏在一笔极小转账之后。一个请求如果在变更账户所有者或权限、授权委托人或包含不透明指令的同时,附带一笔 1 lamport 的转账,那么标题和保存的摘要都只会显示这笔转账。详情中的高风险警告仍然保留,也仍需进行风险确认。共用引擎,iPhone 版同样存在
BTS-08中比特币找零在任意索引上都会被接受。只要某个输出的脚本与钱包任一单签配置相符,无论在分支 0 还是 1、索引最高到 2³¹−1,都会被视为已验证的找零。发往这类地址的资金在审核时显示为“所有输出都回到你的钱包”,但只扫描有限地址范围的钱包可能永远找不到它们。共用引擎,iPhone 版同样存在
BTS-09低至中对于合约调用,保存的摘要不包含原生币金额。一个同时发送原生币的未知 EVM 或 TRON 合约调用,会被保存为“未知合约调用”。审核卡片及其警告会显示这笔金额。共用引擎,iPhone 版同样存在
BTS-10中发布签名密钥存放在开发机上。密钥及其密码以明文保存在工作目录中(已排除在 Git 之外)。发布流程
BTS-11低App 锁屏界面后面,二维码相机可能仍在继续扫描。签名仍然需要钱包密码。Android App
BTS-12低对于完全解码的高风险请求,风险确认只在界面中强制执行。Android App(iPhone 版:BTS-OP5-01)
BTS-13低在 Android 8–11 上发生 Keystore 错误后,用于验证公开钱包数据的密钥可能被重新生成,钱包随后需要“修复”。不会丢失任何机密或资金。Android App
BTS-14低两个辅助密钥没有检查屏幕锁定,部分文档也夸大了保护程度。保险库本身仍然要求设置屏幕锁定。Android App
BTS-15低默认的任务亲和性(task affinity)使旧版 Android 上可能出现任务劫持。Android App
BTS-16低备份检查可以通过反复试错通过。Android App(据报告,iPhone 版相同)
BTS-17低12 词助记词的一张恢复卡片只剩约 40 位熵。Android App
BTS-18低取消钱包匹配后,审核界面可能停留在“正在查找匹配的钱包…”。Android App
BTS-19低Android 8.0–9 无法检测只覆盖确认控件一部分的悬浮层。签名仍然需要密码。Android App

报告还列出了一些信息性说明,例如:引擎线程没有 CPU 时间上限(只影响可用性);在设置单独的上传密钥之前,Google Play 版使用 APK 密钥签名;重试延迟基于系统时钟;以及 JVM 无法擦除的短暂助记词副本。

GPT-6 Astra 评审的是较早的提交。它的发现以及在正式版中的状态:

ID严重程度发现在 e7e71fb 中在 Android 1.0.0 中
BTS-01中部分被遮挡的“签名”和风险确认控件可能透过悬浮层被点按已解决已解决
BTS-02中与极小转账混合的 Solana 销毁或权限变更被摘要显示为那笔转账未解决销毁问题已修复;权限变更问题仍存在,即 BTS-07
BTS-03低操作取消后,机密缓冲区可能残留已解决已解决
BTS-04低带找零的比特币销毁被摘要为“所有输出都回到你的钱包”(即 iPhone 的 R3-01)未解决已修复
BTS-05功能中断的二维码扫描无法恢复已解决已解决
BTS-06验证过时的文件路径导致一项引擎测试失败、另一项未实际运行就通过未解决已修复(217 项引擎测试全部通过)

评审确认了什么​

领域已确认
签名没有绕过密码的方法,除了已审核且已匹配的请求之外无法签署任何内容。签名计划与请求哈希、计划哈希和待签字节摘要绑定;引擎会对照解密后的种子重新解析计划,并拒绝对未签名比特币交易的任何改动。取消、App 锁或新请求之后迟到的结果会被丢弃。
密钥存储原生代码中的 PBKDF2-HMAC-SHA256(600,000 次迭代)、每次加密都使用新随机数和盐的 AES-256-GCM,再加上每个钱包一把不可导出的 Android Keystore 密钥(手机支持时使用 StrongBox)。每次密码尝试都在密钥派生之前计数,计数器损坏时一律拒绝。
内存中的机密解锁后的机密保存在用完即关闭的容器中,即使操作被取消也会被擦除。助记词通过 App 自带的键盘输入,任何输入法都看不到。
引擎宿主引擎包按 SHA-256 和长度固定;QuickJS 在没有 eval 和 Function 的情况下运行,每个涉及机密或不可信输入的操作都使用全新的运行时,并设有内存和栈上限。
离线与平台没有网络权限,也没有联网代码。只导出主界面,没有深层链接;备份和设备迁移被排除在外;所有窗口都不会出现在截图、录屏和最近任务中;在 Android 12 及以上版本会隐藏其他 App 的悬浮层。App 锁永远不能授权签名,发布版不输出任何日志。
供应链在干净的 npm ci --ignore-scripts 之后重新构建的引擎,与已提交的文件和 APK 中的副本逐字节一致。生产依赖审计没有报告任何安全公告。

评审未覆盖的内容​

未覆盖的内容包括:真机测试(不同厂商的 Keystore 与 StrongBox 行为、生物识别、悬浮层、屏幕捕获)、恶意悬浮层攻击演练、侧信道、原生代码在 ARM 上的执行、真实区块链上的交易、Maven 和原生依赖的 CVE 扫描,以及 Google Play 构建的副本。两份报告都要求在 Android 8 到最新版本的代表性设备上检验发布版,Opus 5.5 还建议在这款 App 保护大额资金之前进行独立的人工审计。

验证 APK 和引擎​

在 bittool.com/signer 发布的 APK 可以完整核验:文件哈希、签名证书、其中的引擎,以及没有网络权限(aapt2 dump badging 列出的权限中没有 android.permission.INTERNET)。

# 1. The APK from bittool.com/signer
shasum -a 256 BitToolSigner-1.0.0-1000001.apk
# 109dbf5c622ee77672904c34a10229df3c9b0eac45b07096c510b1e1e169c2a4
apksigner verify --print-certs BitToolSigner-1.0.0-1000001.apk
# Signer #1 certificate DN: CN=BITTOOL PTE. LTD., O=BITTOOL PTE. LTD., C=SG
# Signer #1 certificate SHA-256 digest: af41ed101765393ae89038eb4c6fc7fa96d930f6fcd76b881437a39b5a9e4631

# 2. The engine inside it
unzip -p BitToolSigner-1.0.0-1000001.apk assets/engine/signer.js | shasum -a 256
# 4b3717599e8ee3ed9d2480e640e7203731543cc8ab0f2c3cec3b78e6f400fa19 (1,181,432 bytes)

# 3. The same engine, rebuilt from source
git clone https://github.com/bitbill/bittool-signer-android
cd bittool-signer-android && git checkout 71af693
cd engine && npm ci --ignore-scripts && npm run build
shasum -a 256 ../core/engine/src/main/assets/engine/signer.js

证书在各个版本之间永不改变,Android 只会安装带有相同证书的更新,App 也会在“设置 › 完全开源 › 本次构建”中显示它。从 Google Play 安装的副本是另一个文件,因为 Google Play 会根据上传的包重新构建,所以无法比对它的哈希;但其中的 assets/engine/signer.js 不会改变,可以在 adb pull 之后用同样的方法比对。完整步骤见代码仓库中的 Reproducible-Build.md。我们已于 2026 年 10 月 25 日对照发布的 APK 核对了上述数值。

下载报告​

报告页数SHA-256
iPhone · Opus 5,2026 年 10 月 19 日(PDF,118 KB)17ff7ddd17e5dffccd99db6aaa43b8f0041167b58bd9b2bd7cc11d185e779bca1a
iPhone · GPT-6 Astra,报告 R3,2026 年 10 月 18 日(PDF,46 KB)1602d7a358f8f35b2978eab7db1292add4365a94b736ff79e158dee3afb842b64a
Android · Opus 5.5,2026 年 10 月 25 日(PDF,252 KB)88242d58aeec1aa88823eb0a938c9461b0681abfab3f37805e2f77a41b3bba34c
Android · GPT-6 Astra,复审,2026 年 10 月 24 日(PDF,22 KB)7b37aaefd40d0d522384a86255accadeb976067175d76e38466a1b4c90b036f53

本页的摘要由我们撰写;如果与报告的措辞有出入,以报告为准。