Scallop Protocol 预言机 DoS 漏洞分析
一份关于 Sui 生态借贷协议 Scallop 的价格预言机拒绝服务漏洞的技术分析。
背景
Scallop 是 Sui 链上最大的借贷协议之一。2026 年 6 月,我在审计其价格预言机模块时发现了一个严重的设计缺陷——预言机更新机制中的时间戳等值校验导致协议大部分时间处于不可用状态。
漏洞详情
问题代码
在 price.move 的 get_price() 函数中,核心逻辑是:
public fun get_price(oracle: &Oracle): u64 {
let now = clock.timestamp_seconds();
assert!(now == last_updated, EMockOracleNotUpdated);
}
它要求 now == last_updated,即预言机更新的时间戳必须和当前交易执行的时间戳精确到同一秒。
为什么这是 DoS
预言机的 update_price() 每 30 秒才允许调用一次:
public fun update_price(oracle: &mut Oracle, new_price: u64) {
let now = clock.timestamp_seconds();
assert!(now - last_updated >= 30, EMockOracleTooFrequent);
}
所以在 30 秒窗口内,last_updated 是不变的。而 get_price() 要求 now == last_updated,意味着只有在预言机刚更新完的那一秒内调用才会成功。
可用性计算:
- 每 30 秒有 1 秒可用
- 可用率 ≈ 3.3%
- 换句话说,96.7% 的时间内协议的核心功能都处于拒绝服务状态
影响范围
受影响的函数包括:
borrow()— 无法借贷withdraw_collateral()— 无法提取抵押品liquidate()— 最致命!市场暴跌时无法清算,导致坏账累积
攻击场景
假设 BTC 价格瞬间暴跌 50%(虽然极端,但加密市场这种事发生过):
- 大量借款人的抵押率跌破清算线
- 清算人调用
liquidate()→ 触发get_price()→now != last_updated→ 交易 revert - 坏账不断累积
- 协议资不抵债
修复建议
用时间窗口检查替代精确等值:
const MAX_PRICE_AGE_SECONDS: u64 = 10;
public fun get_price(oracle: &Oracle): u64 {
let now = clock.timestamp_seconds();
assert!(now - last_updated <= MAX_PRICE_AGE_SECONDS, EMockOracleStale);
}
这样在预言机更新后的 10 秒内都能正常报价,可用率从 3.3% 提升到 33%,同时又能保证价格不会过时。
一些感想
这个漏洞严格来说是"设计缺陷"而非"代码 bug"。设计者的意图可能是强制用户使用最新价格,但用 == 来约束时间戳显然没有考虑现实中的交易延迟和并发场景。
智能合约安全不只是防重入、防溢出,经济模型和逻辑设计的边界情况同样致命。
后续
这份报告我没有提交给项目方。原因?没有上链验证,纯理论分析。搞安全的人最忌讳拿着理论问题去要赏金——万一人家链上根本不是这套逻辑,尴尬的是自己。
留在这里当学习笔记吧。
