这篇文章深入分析了ERC-4337账户抽象技术中的六种主要安全漏洞,如签名重放、支付大师滥用和模块隔离不足等。作者强调了这些漏洞的复杂性和相互作用,并指出在部署账户抽象逻辑前进行全面威胁建模和审计的必要性,尤其是在AI代理应用场景中。
账户抽象本应简化用户体验。它确实做到了——但它将安全负担从单一的加密原语(私钥)转移到一个可编程系统上,而大多数团队没有能力正确地审计这个系统。
本周,Trail of Bits 发布了他们对 ERC-4337 智能账户中六种错误类别的分析。他们识别出的模式与我们实际遇到的情况一致。本文将超越分类法——我们将向你展示这些故障在生产代码中是什么样子,它们为什么会相互加剧,以及在发布任何账户抽象逻辑之前,你的团队需要做什么。
传统的 EOA 钱包只有一条规则:控制私钥,就控制了账户。它简单粗暴,不灵活,从安全角度来看,它是可预测的。
ERC-4337 用你账户合约上的 validateUserOp 函数取代了这一点。该函数现在是信任边界。下游的所有假设——调用者已获授权,nonce 有效,paymaster 没有被滥用——都源于你在其中编写的逻辑。
这是核心问题:一个以前由密码学保护的系统现在由代码保护。而代码有 Bug。
EVM 执行环境并不关心你的 validateUserOp 是否逻辑健全。它将执行你编写的任何内容。bundler 将转发 UserOperation。EntryPoint 将调用你的账户。如果你哪里出错了,它就会被利用。
最基本的错误:验证签名时没有将其绑定到 nonce 或链 ID。我们发现,当团队将 EOA 签名方案直接移植到 validateUserOp 中,而没有考虑新的执行上下文时,就会出现这种情况。
1// 存在漏洞 — 没有绑定 chainId 或 nonce
2function validateUserOp(
3 UserOperation calldata userOp,
4 bytes32 userOpHash,
5 uint256 missingAccountFunds
6) external returns (uint256 validationData) {
7 bytes32 hash = keccak256(abi.encode(userOp.callData));
8 address recovered = ECDSA.recover(hash, userOp.signature);
9 if (recovered != owner) return SIG_VALIDATION_FAILED;
10 return 0;
11}
如果攻击者在 Arbitrum 上截获了有效的 UserOperation,并且相同的账户部署在相同的地址(CREATE2 常见的情况),他就可以在主网上重放它。nonce 由 EntryPoint 检查,但前提是你的实现正确地递增了它——并且只针对同一条链上的同一个 EntryPoint。
解决方案是直接使用 userOpHash(它已经包含 chainId 和 EntryPoint 地址),而不是独立地重新哈希 callData。
Paymaster 赞助 gas。仅凭这句话就应该触发一次威胁建模会议。任何同意支付他人操作的合约都具有明显的经济攻击面。
这里的故障模式是 paymaster 在验证赞助意图时没有强制执行执行约束。paymaster 可能会在 validatePaymasterUserOp 时检查“这个用户在我们的白名单上吗”,然后在 postOp 时没有强制执行实际的 callData 是否与预期匹配。
结果:白名单用户提交意外的 callData,可能耗尽 EntryPoint 中 paymaster 的存款。
validateUserOp 返回一个 uint256,其中打包了时间范围(validAfter、validUntil)和签名验证状态位。这种打包方式不直观,团队经常返回原始错误代码,而 EntryPoint 将其解释为有时限的有效窗口。
从 EntryPoint 的角度来看,在所有上下文中返回 1 并不意味着“无效”——它可能意味着“有效但已过期”,具体取决于位的设置方式。我们曾见过一些旨在拒绝操作的实现,却无意中打包了 EntryPoint 视为有效的返回值。
EntryPoint 的 _validateAccountAndPaymasterValidationData 使用位掩码提取这些字段。你的返回值必须使用 _packValidationData 辅助函数或等效方法构造,而不是作为原始的成功/失败整数返回。
ERC-4337 账户越来越多地使用插件/模块架构——验证模块、执行模块、回退处理器。承诺是可组合性。风险在于一个恶意或有缺陷的模块可能会损害整个账户。
这类似于我们升级模式安全指南中记录的代理模式漏洞:账户成为一个信任聚合器,聚合体的安全性等于其安装的最弱组件的安全性。
具体的故障是:没有强制执行访问控制的模块安装函数。如果任何人都可以调用 installModule(address module),攻击者就会用一个覆盖 validateUserOp 以对任何签名返回成功的模块来调用它。
1// 存在漏洞 — 模块安装上没有访问控制
2function installModule(address module, bytes calldata initData) external {
3 IModule(module).onInstall(initData);
4 _modules[module] = true;
5}
ERC-4337 规范限制了 validateUserOp 函数在 bundler 模拟期间可以访问哪些存储槽。这些限制旨在防止模拟灰盒攻击——在模拟期间看起来有效但在链上失败的操作,因为另一个交易在模拟和执行之间修改了共享状态。
具体来说,validateUserOp 不能从与账户自身地址或发送者的 UserOperation 不相关的存储槽中读取数据。从任意全局状态(共享价格预言机、第三方注册表)读取数据违反了这些约束,并将导致 bundler 丢弃你的操作。
讽刺的是,这个限制通常只有在生产环境中才能被发现,那时操作莫名其妙地未能上链。Bundler 不总是明确地显示存储访问违规的错误消息。
社交恢复是 ERC-4337 最引人注目的功能之一,也是其最经常被搞砸的实现之一。失败通常不是直接盗窃——它是一种灰盒攻击机制,可以永久性地将用户锁定在其账户之外。
允许任何守护者发起恢复(但需要阈值批准才能完成)的恢复方案,会创建一个窗口,对抗性守护者可以在其中垃圾邮件式地发送启动交易,重置恢复计时器并阻止合法恢复完成。如果你的恢复模块使用带有固定窗口的 recoveryInitiatedAt 时间戳,单个恶意守护者可以以 gas 成本无限期地阻止恢复。
这六种故障模式很少单独出现。真正的危险在于它们如何相互作用。
验证松懈的 paymaster(故障模式 2)与没有隔离的模块系统(故障模式 4)相结合,意味着白名单用户可以安装恶意模块,利用 paymaster 赞助该模块的安装 gas,然后从团队认为已锁定的账户执行任意调用。
这就是为什么智能账户的威胁建模不能逐个合约地进行。你需要对完整的操作生命周期进行建模:UserOperation 构建 → bundler 模拟 → EntryPoint 验证 → 账户执行 → paymaster 后操作。
我们经常遇到的一个误解:团队认为 bundler 和 EntryPoint 充当安全层。它们不是——它们充当一个执行层,强制执行 ERC-4337 协议规则,而不是你应用程序的业务逻辑。
EntryPoint 将忠实地执行通过 validateUserOp 的 UserOperation,即使该操作耗尽账户、安装恶意模块或将所有权转移给攻击者。EntryPoint 的职责是协议合规性。安全是你的职责。
这直接映射到纵深防御原则:基础设施为你提供了一个框架,而不是保证。你拥有的每一层都必须独立安全。
在提交你的智能账户实现进行审计或部署之前,请检查以下各项:
验证阶段:
userOpHash 进行签名绑定,还是重新构造了一个忽略链 ID 或 EntryPoint 地址的哈希?validateUserOp 是否访问了不属于账户地址的任何存储?明确测试 bundler 模拟。Paymaster:
callData 并且仍然获得赞助?模块系统:
恢复:
单个守护者是否可以灰盒攻击恢复过程?
所有权变更是否有时锁,给合法所有者留出响应时间?
如果在之前的恢复正在进行时启动恢复,行为会是怎样?
本周,Trail of Bits 还发布了关于代理浏览器隔离失败的文章——与智能账户安全的重叠并非巧合。
AI 代理越来越多地被连接到 ERC-4337 智能账户,作为其链上执行层。代理发送 UserOperation,智能账户验证并执行它们。这创造了一个新的威胁面:如果代理可以通过 prompt injection(针对代理浏览器的已证明攻击向量)被操纵,攻击者不需要破坏密钥——他们需要破坏代理的意图。
假设“如果签名有效,则意图已获授权”的验证逻辑在代理上下文中完全失效。我们预计这将成为 2026 年主要的审计重点类别。
对于构建代理控制账户的团队:验证不仅要约束签名的真实性,还要约束操作的语义。支出限制、调用目标白名单和执行速率限制应属于 validateUserOp 或专用执行模块中——而不是作为代理系统 prompt 中的事后考虑。
审计你的 validateUserOp 返回值构造。如果你没有使用 EntryPoint 的 _packValidationData 辅助函数,或者没有针对 EntryPoint 的解包逻辑明确测试你的返回值,那么你的信任边界中存在未经测试的代码。
在主网之前,使用真实的 bundler 运行 bundler 模拟。在本地,你的操作通过。符合规范的 bundler 运行存储访问验证可能会静默拒绝它们。在测试期间,针对生产 bundler 端点使用 eth_estimateUserOperationGas。
将模块安装视为特权操作。每个安装的模块都有效地扩展了你的信任边界。像审查你自己的实现一样仔细审查其 validateUserOp 实现。
模拟你的 paymaster 的最坏情况经济学。攻击者耗尽你的 paymaster 存款需要多少成本?如果答案是“少于存款”,则需要额外的约束。
如果你正在构建代理控制的账户,请进行专门的审计。可编程验证和外部意图生成的结合是一个新的攻击面。为人类控制的智能账户编写的清单不足以应对。
如果你正在交付 ERC-4337 智能账户基础设施——无论是作为钱包 SDK、协议的会话密钥系统,还是代理执行层——在最终部署之前联系我们进行审计。安全顾问服务模式对于在发布后迭代账户逻辑的团队特别有效:随着模块注册表的增长进行持续审查,而不是一次性快照。
ERC-4337 智能账户功能强大,但它们引入的可编程验证面需要超出传统智能合约审查的审计专业知识。在 Zealynx Security,我们审计完整的 UserOperation 生命周期:账户验证、paymaster 逻辑、模块系统和恢复流程。
正在构建或集成账户抽象?在部署之前对整个执行管道进行审查。请求 EVM 审计范围 ->
参考文献:
ERC-4337 是一个以太坊标准,用可编程智能合约钱包取代了传统的外部拥有账户 (EOA)。账户的验证逻辑在代码中定义,而不是由单一私钥控制账户——从而实现多重签名、社交恢复、支出限制以及通过 paymaster 实现无 gas 交易等功能。
传统的智能合约有一组定义的入口点。ERC-4337 引入了一个多组件执行管道——账户、bundler、EntryPoint、paymaster 和可选模块——每个都有自己的信任假设。任何组件中的漏洞都可能危及整个账户,而且这些交互比独立合约更难理解。
UserOperation 是 ERC-4337 中的一个结构体,用于描述用户意图(类似于交易),但不直接提交到区块链。相反,它发送给 bundler,bundler 通过 EntryPoint 合约将多个 UserOperation 打包成一个链上交易。关键区别在于验证逻辑是可编程的——智能账户决定是否接受操作,而不仅仅是加密签名检查。
是的。如果 paymaster 在验证赞助时没有限制它赞助的操作,攻击者可以制作消耗最大 gas 且没有任何实际用途的 UserOperation。paymaster 从其 EntryPoint 存款中支付 gas,重复滥用可能会完全耗尽它。合适的 paymaster 必须验证操作 calldata 并强制执行 gas 限制。
当智能账户使用 CREATE2 部署在确定性地址上时,相同的账户地址存在于多条链上。如果签名验证没有绑定到特定的链 ID,为一条链签名的有效 UserOperation 可以在另一条链上重放。解决方案是使用 EntryPoint 提供的 userOpHash,它包含链 ID 和 EntryPoint 地址。
绝对是。标准的 DeFi 审计是孤立地审查合约逻辑。ERC-4337 审计必须涵盖完整的 UserOperation 生命周期——验证逻辑、返回值打包、模拟期间的存储访问限制、paymaster 经济学、模块安装访问控制和恢复流程灰盒攻击向量。bundler 模拟模型增加了传统合约执行中不存在的约束。
| Term | Definition |
|---|---|
| Account Abstraction | 一种设计模式,用可编程的智能合约账户取代固定的 EOA 逻辑,从而实现自定义验证、恢复和 gas 支付机制。 |
| UserOperation | ERC-4337 中的一个结构体,用于编码用户意图,包括 calldata、gas 限制和签名,提交给 bundler 而不是直接提交到区块链。 |
| Bundler | 一个链下参与者,负责收集 UserOperation,对其进行模拟,并将有效的 UserOperation 作为单个链上交易提交给 EntryPoint 合约。 |
| Paymaster | 一个智能合约,为 UserOperation 赞助 gas,从而为终端用户实现无 gas 交易,以换取替代支付或白名单。 |
| EntryPoint | ERC-4337 中的单例合约,负责协调所有智能账户的 UserOperation 验证、执行和 gas 核算。 |
| Social Recovery | 一种钱包恢复机制,当主密钥丢失或泄露时,指定的守护者可以共同授权所有权变更。 |
| Session Key | 一个临时且有范围的密钥,将有限权限委托给 dApp 或代理,而无需暴露主账户签名者。 |
- 原文链接: zealynx.io/blogs/erc-433...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!