就在12月3日,Aave部署V2版本后的第二天,我们随手翻看代码,竟发现一个能搞垮整个Aave的致命漏洞。这个漏洞潜伏在V1和V2两个版本中,经过了5家安全公司的审查,甚至有人用了形式化验证,却全都没发现。
Aave用了代理模式来升级合约,这本身很常见。每个组件分成逻辑合约和代理合约,用户跟代理交互,代理再去调用逻辑合约里的代码。这样做的好处是升级时只要换逻辑合约就行,数据都存在代理里。
问题就出在两个地方。一是逻辑合约里的函数可以直接被人调用,包括那些本该只能调一次的初始化函数。二是初始化函数里有个调节器,本意是防止重复初始化,但设计上允许在特定条件下再次调用。
任何人都能动手脚
漏洞的核心在于逻辑合约里的初始化函数。这个函数用来设置提供者地址,本来应该只能由系统自己调一次。但因为逻辑合约是公开的,任何人都能直接在上面调用这个函数。
只要有人抢先调用,就能把自己的地址设为提供者。这下好了,整个逻辑合约就等于被人控制了,想干什么都行。本来应该保护资金的代码,瞬间变成了别人的后门。
破坏性远超想象
光是破坏逻辑合约已经很可怕了,但更糟的是代理合约还有个隐患。我们早在2018年就提醒过,有些合约的代理在调用失败时会返回成功,让人以为操作完成了。Aave的代理就有这个问题。
如果代理调用了一个被破坏的逻辑合约,表面上会返回成功,实际上啥都没干。用户存钱进去,钱就没了,因为那些代币网关里存的资产会被别人直接拿走。外部合约也会被坑,以为操作成功了,实际上逻辑全乱了。
哪些合约遭殃
受影响的不只是Aave自己,所有跟它交互的外部DeFi合约都悬了。比如那些靠Aave存款、借贷来运转的协议,一旦Aave的借贷池逻辑被破坏,它们的基本逻辑就被打破了。
我们没能力列出所有受影响的合约,但可以确定的是,像资产网关这类存储用户资金的地方最危险。用户调用存款,结果啥也没发生,钱还在网关里,就成了别人的盘中餐。
安全审查为啥失效
Aave的代码经过形式化验证,很多人都觉得这种高级验证应该万无一失。但实际上,形式化验证只能证明某些特定属性,比如某个函数会不会改状态。
验证报告里列的都是一些局部属性,根本没考虑到可升级这个整体架构下的风险。在多合约交互的环境里,要完整证明安全性极其困难,所以验证往往只能覆盖一小块,漏洞就钻了空子。
吸取教训快速修复
好在Aave团队反应够快,我们报告后一小时他们就修复了。调用了销毁函数把两个版本的借贷池都保护起来,漏洞还没来得及被人利用。之后他们要做的,是在所有逻辑合约的构造函数里彻底禁用初始化,还要检查代理有没有代码。
这件事提醒我们,安全审查不能迷信单一技术。自动化工具几秒钟就能发现这种问题,有经验的人也能快速定位,但形式化验证反而因为太专注局部错过了全局风险。开发者在部署前,一定要把安全工具集成到流程里,给审查留足时间,特别是可升级这块,得多花心思研究。
你有没有想过,你信任的那些经过多家安全公司审计的DeFi协议,会不会也藏着类似的致命漏洞?欢迎在评论区分享你的看法,点赞转发让更多人看到这个真实案例。







