Reproduced Exploit
Shiny Pawn — off-chain offer amount creates underwater loans
Pawn trusts a backend-signed offerAmount without checking collateral value on-chain, then permits liquidation only after a deadline. A price drop during the term creates bad debt that cannot be liquidated early.
Chain
Other
Category
oracle
Date
Jan 2025
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 64681-h-01-protocol-insolvency-risk-due-to-lack-of-on-chain-oracle. Standalone Foundry PoC and full write-up: 64681-h-01-protocol-insolvency-risk-lack-on-chain-oracle_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/oracle/missing-validation · vuln/logic/liquidation-logic
Reproduction: local synthetic Foundry reduction; the complete passing trace is in output.txt.
Key info#
| Field | Value |
|---|---|
| Loss | A collateral fall leaves 200 units of modeled bad debt; no live funds are moved. |
| Vulnerable contract | Pawn.pawn / Pawn.liquidate in test/64681-h-01-protocol-insolvency-risk-lack-on-chain-oracle.sol |
| Attacker EOA | 0x1111111111111111111111111111111111111111 |
| Attack contract | Exploit |
| Attack tx | Local Foundry Exploit.run() |
| Chain · block · date | Ethereum model · block 0 · synthetic |
| Compiler | Solidity ^0.8.24 |
| Bug class | Missing on-chain LTV oracle and health-based liquidation |
TL;DR#
Pawn trusts a backend-signed offerAmount without checking collateral value on-chain, then permits liquidation only after a deadline. A price drop during the term creates bad debt that cannot be liquidated early.
Background#
RWA-backed lending needs an on-chain valuation or conservative LTV bound. A time-only liquidation condition cannot respond to an underwater position while the loan is still active.
The vulnerable code#
function pawn(uint256 collateralValue, uint256 offerAmount, uint256 deadline) external returns (uint256 id) {
// @> VULN: signed offer is accepted without on-chain LTV/oracle validation.
id = nextId++;
positions[id] = Position(offerAmount, collateralValue, deadline, true);
}
Root cause#
The protocol imports risk decisions from an off-chain signer and exposes no health-factor liquidation path. When collateral falls, borrower incentives and protocol recovery diverge.
Preconditions#
- A backend signs an offer near the maximum intended LTV.
- Collateral value drops before the loan deadline.
liquidatechecks onlynow >= deadline.
Attack walkthrough#
- Originate 1,800 against a 2,000 appraisal with deadline 1,000.
- Update modeled collateral to 1,600.
- Liquidation at timestamp 500 reverts;
badDebtis 200. See output.txt:4.
Diagrams#
Remediation#
Validate offerAmount <= collateralValue * maxLtv against a trusted, fresh oracle at origination. Add health-factor liquidation during the term, normalize decimals, and define stale-feed behavior.
How to reproduce#
cd evm-hack-registry/64681-h-01-protocol-insolvency-risk-lack-on-chain-oracle_exp
forge test -vvvvv
Sources#
Reference: https://github.com/shieldify-security/audits-portfolio-md/blob/main/Shiny-Security-Review.md
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 64681-h-01-protocol-insolvency-risk-lack-on-chain-oracle_exp (evm-hack-registry mirror).
- AuditVault finding: 64681-h-01-protocol-insolvency-risk-due-to-lack-of-on-chain-oracle.
Alerts & third-party analyses
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.