solidity-argus 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +3 -3
- package/README.md +93 -37
- package/package.json +33 -7
- package/skills/INVENTORY.md +88 -57
- package/skills/README.md +26 -23
- package/skills/case-studies/beanstalk-governance/SKILL.md +52 -0
- package/skills/case-studies/bzx-flash-loan/SKILL.md +53 -0
- package/skills/case-studies/cream-finance/SKILL.md +52 -0
- package/skills/case-studies/curve-reentrancy/SKILL.md +52 -0
- package/skills/case-studies/dao-hack/SKILL.md +51 -0
- package/skills/case-studies/euler-finance/SKILL.md +52 -0
- package/skills/case-studies/harvest-finance/SKILL.md +52 -0
- package/skills/case-studies/level-finance/SKILL.md +51 -0
- package/skills/case-studies/mango-markets/SKILL.md +53 -0
- package/skills/case-studies/nomad-bridge/SKILL.md +51 -0
- package/skills/case-studies/parity-multisig/SKILL.md +55 -0
- package/skills/case-studies/poly-network/SKILL.md +51 -0
- package/skills/case-studies/rari-fuse/SKILL.md +51 -0
- package/skills/case-studies/ronin-bridge/SKILL.md +52 -0
- package/skills/case-studies/wormhole-bridge/SKILL.md +51 -0
- package/skills/manifests/smartbugs.json +1 -3
- package/skills/manifests/sunweb3sec.json +1 -3
- package/skills/vulnerability-patterns/access-control/SKILL.md +14 -0
- package/skills/vulnerability-patterns/arbitrary-storage-location/SKILL.md +13 -1
- package/skills/vulnerability-patterns/assert-violation/SKILL.md +8 -1
- package/skills/vulnerability-patterns/asserting-contract-from-code-size/SKILL.md +12 -1
- package/skills/vulnerability-patterns/authorization-txorigin/SKILL.md +2 -1
- package/skills/vulnerability-patterns/cross-chain-bridge-vulnerabilities/SKILL.md +217 -0
- package/skills/vulnerability-patterns/default-visibility/SKILL.md +13 -1
- package/skills/vulnerability-patterns/delegatecall-untrusted-callee/SKILL.md +2 -1
- package/skills/vulnerability-patterns/dos-gas-limit/SKILL.md +8 -1
- package/skills/vulnerability-patterns/dos-revert/SKILL.md +1 -0
- package/skills/vulnerability-patterns/erc4626-exchange-rate-manipulation/SKILL.md +64 -0
- package/skills/vulnerability-patterns/fee-on-transfer-tokens/SKILL.md +93 -0
- package/skills/vulnerability-patterns/flash-loan-attacks/SKILL.md +1 -0
- package/skills/vulnerability-patterns/floating-pragma/SKILL.md +8 -1
- package/skills/vulnerability-patterns/front-running-attacks/SKILL.md +209 -0
- package/skills/vulnerability-patterns/gas-optimization-patterns/SKILL.md +203 -0
- package/skills/vulnerability-patterns/governance-attacks/SKILL.md +208 -0
- package/skills/vulnerability-patterns/hash-collision/SKILL.md +8 -1
- package/skills/vulnerability-patterns/inadherence-to-standards/SKILL.md +12 -1
- package/skills/vulnerability-patterns/incorrect-constructor/SKILL.md +8 -1
- package/skills/vulnerability-patterns/incorrect-inheritance-order/SKILL.md +8 -1
- package/skills/vulnerability-patterns/insufficient-gas-griefing/SKILL.md +12 -1
- package/skills/vulnerability-patterns/lack-of-precision/SKILL.md +7 -1
- package/skills/vulnerability-patterns/logic-errors/SKILL.md +10 -0
- package/skills/vulnerability-patterns/missing-parameter-bounds/SKILL.md +44 -0
- package/skills/vulnerability-patterns/missing-protection-signature-replay/SKILL.md +17 -1
- package/skills/vulnerability-patterns/msgvalue-loop/SKILL.md +12 -1
- package/skills/vulnerability-patterns/off-by-one/SKILL.md +7 -1
- package/skills/vulnerability-patterns/oracle-manipulation/SKILL.md +9 -0
- package/skills/vulnerability-patterns/outdated-compiler-version/SKILL.md +8 -1
- package/skills/vulnerability-patterns/overflow-underflow/SKILL.md +1 -0
- package/skills/vulnerability-patterns/proxy-vulnerabilities/SKILL.md +209 -0
- package/skills/vulnerability-patterns/reentrancy/SKILL.md +9 -0
- package/skills/vulnerability-patterns/shadowing-state-variables/SKILL.md +8 -1
- package/skills/vulnerability-patterns/share-accounting-desynchronization/SKILL.md +44 -0
- package/skills/vulnerability-patterns/signature-malleability/SKILL.md +2 -1
- package/skills/vulnerability-patterns/stateful-parameter-update-drift/SKILL.md +44 -0
- package/skills/vulnerability-patterns/unbounded-return-data/SKILL.md +12 -1
- package/skills/vulnerability-patterns/unchecked-return-values/SKILL.md +2 -1
- package/skills/vulnerability-patterns/unencrypted-private-data-on-chain/SKILL.md +8 -1
- package/skills/vulnerability-patterns/unexpected-ecrecover-null-address/SKILL.md +8 -1
- package/skills/vulnerability-patterns/uninitialized-storage-pointer/SKILL.md +8 -1
- package/skills/vulnerability-patterns/unsafe-erc20-transfers/SKILL.md +132 -0
- package/skills/vulnerability-patterns/unsafe-low-level-call/SKILL.md +12 -1
- package/skills/vulnerability-patterns/unsecure-signatures/SKILL.md +12 -1
- package/skills/vulnerability-patterns/unsupported-opcodes/SKILL.md +11 -1
- package/skills/vulnerability-patterns/unused-variables/SKILL.md +8 -1
- package/skills/vulnerability-patterns/use-of-deprecated-functions/SKILL.md +8 -1
- package/skills/vulnerability-patterns/weak-sources-randomness/SKILL.md +8 -1
- package/skills/vulnerability-patterns/weird-tokens/SKILL.md +10 -0
- package/skills/vulnerability-patterns/zero-address-misconfiguration/SKILL.md +48 -0
- package/src/agents/argus-prompt.ts +24 -7
- package/src/agents/pythia-prompt.ts +3 -4
- package/src/agents/scribe-prompt.ts +7 -2
- package/src/agents/sentinel-prompt.ts +32 -3
- package/src/cli/cli-program.ts +29 -26
- package/src/cli/commands/check-skills.ts +135 -0
- package/src/cli/commands/doctor.ts +48 -26
- package/src/cli/commands/init.ts +5 -3
- package/src/cli/commands/install.ts +7 -5
- package/src/cli/commands/lint-skills.ts +16 -12
- package/src/cli/index.ts +5 -5
- package/src/cli/types.ts +3 -3
- package/src/config/index.ts +1 -1
- package/src/config/loader.ts +4 -6
- package/src/config/schema.ts +4 -5
- package/src/config/types.ts +2 -2
- package/src/constants/defaults.ts +2 -0
- package/src/create-hooks.ts +145 -34
- package/src/create-managers.ts +10 -8
- package/src/create-tools.ts +13 -9
- package/src/features/background-agent/background-manager.ts +93 -87
- package/src/features/background-agent/index.ts +1 -1
- package/src/features/context-monitor/context-monitor.ts +3 -3
- package/src/features/context-monitor/index.ts +2 -2
- package/src/features/error-recovery/session-recovery.ts +2 -4
- package/src/features/error-recovery/tool-error-recovery.ts +12 -7
- package/src/features/index.ts +5 -5
- package/src/features/persistent-state/audit-state-manager.ts +143 -60
- package/src/features/persistent-state/global-run-index.ts +38 -0
- package/src/features/persistent-state/index.ts +1 -1
- package/src/features/persistent-state/run-journal.ts +86 -0
- package/src/hooks/config-handler.ts +28 -11
- package/src/hooks/context-budget.ts +2 -5
- package/src/hooks/event-hook.ts +47 -23
- package/src/hooks/hook-system.ts +4 -4
- package/src/hooks/index.ts +5 -5
- package/src/hooks/knowledge-sync-hook.ts +18 -21
- package/src/hooks/recon-context-builder.ts +2 -2
- package/src/hooks/safe-create-hook.ts +6 -7
- package/src/hooks/tool-tracking-hook.ts +104 -50
- package/src/hooks/types.ts +2 -1
- package/src/index.ts +23 -36
- package/src/knowledge/retry.ts +22 -22
- package/src/knowledge/scvd-client.ts +88 -95
- package/src/knowledge/scvd-errors.ts +35 -35
- package/src/knowledge/scvd-index.ts +78 -80
- package/src/knowledge/scvd-sync.ts +106 -101
- package/src/managers/index.ts +1 -1
- package/src/managers/types.ts +19 -14
- package/src/plugin-interface.ts +7 -9
- package/src/shared/binary-utils.ts +44 -35
- package/src/shared/deep-merge.ts +55 -36
- package/src/shared/file-utils.ts +21 -19
- package/src/shared/index.ts +11 -5
- package/src/shared/jsonc-parser.ts +123 -28
- package/src/shared/logger.ts +16 -3
- package/src/shared/project-utils.ts +30 -0
- package/src/skills/analysis/cluster.ts +414 -0
- package/src/skills/analysis/gates.ts +227 -0
- package/src/skills/analysis/index.ts +33 -0
- package/src/skills/analysis/normalize.ts +217 -0
- package/src/skills/analysis/similarity.ts +224 -0
- package/src/skills/argus-skill-resolver.ts +17 -6
- package/src/skills/skill-schema.ts +11 -10
- package/src/solodit-lifecycle.ts +202 -0
- package/src/state/audit-state.ts +8 -8
- package/src/state/finding-store.ts +68 -55
- package/src/state/types.ts +88 -67
- package/src/tools/argus-skill-load-tool.ts +12 -7
- package/src/tools/contract-analyzer-tool.ts +60 -77
- package/src/tools/forge-coverage-tool.ts +226 -0
- package/src/tools/forge-fuzz-tool.ts +127 -127
- package/src/tools/forge-test-tool.ts +153 -157
- package/src/tools/gas-analysis-tool.ts +264 -0
- package/src/tools/pattern-checker-tool.ts +185 -190
- package/src/tools/pattern-loader.ts +5 -111
- package/src/tools/proxy-detection-tool.ts +224 -0
- package/src/tools/report-generator-tool.ts +268 -200
- package/src/tools/slither-tool.ts +266 -218
- package/src/tools/solodit-search-tool.ts +216 -119
- package/src/tools/sync-knowledge-tool.ts +7 -11
- package/src/utils/audit-artifact-detector.ts +28 -29
- package/src/utils/dependency-scanner.ts +37 -37
- package/src/utils/project-detector.ts +111 -124
- package/src/utils/solidity-parser.ts +103 -74
- package/skills/patterns/access-control.yaml +0 -31
- package/skills/patterns/erc4626.yaml +0 -29
- package/skills/patterns/flash-loan.yaml +0 -20
- package/skills/patterns/oracle.yaml +0 -30
- package/skills/patterns/proxy.yaml +0 -30
- package/skills/patterns/reentrancy.yaml +0 -30
- package/skills/patterns/signature.yaml +0 -31
- package/src/hooks/event-hook-v2.ts +0 -99
- package/src/state/plugin-state.ts +0 -14
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: beanstalk-governance
|
|
3
|
+
description: "Case study of the 2022 Beanstalk exploit: flash loan + governance manipulation draining ~$182M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/beanstalk-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: 'propose\(.*\)'
|
|
10
|
+
severity: "Medium"
|
|
11
|
+
description: "Detects governance proposal functions. Critical to check if voting power can be acquired via flash loans."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# Beanstalk Governance (2022)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In April 2022, Beanstalk Farms, a decentralized credit-based stablecoin protocol, was exploited for approximately $182 million. The attacker used a flash loan to acquire a massive amount of the protocol's governance token (Stalk), allowing them to pass a malicious governance proposal and drain the protocol's reserves.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The vulnerability was in the protocol's governance mechanism, which allowed users to gain voting power (Stalk) by depositing assets into the "Silo". Crucially, the protocol did not prevent users from using flash-loaned assets to gain this voting power and immediately vote on proposals. The attacker used this to reach the 67% supermajority required to execute a "BIP" (Beanstalk Improvement Proposal) instantly.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. Attacker took a massive flash loan from Aave, Uniswap, and SushiSwap (including ~350M DAI, 500M USDC, 150M USDT, 32M BEAN, and 11M LUSD).
|
|
26
|
+
2. Attacker deposited these assets into the Beanstalk Silo to gain a huge amount of Stalk (voting power).
|
|
27
|
+
3. Attacker had already submitted two malicious proposals (BIP-18 and BIP-19) one day prior.
|
|
28
|
+
4. With the flash-loaned Stalk, the attacker voted in favor of their own proposals, reaching the 67% threshold.
|
|
29
|
+
5. The proposals were executed immediately, sending all assets in the Beanstalk Silo to the attacker's address.
|
|
30
|
+
6. Attacker repaid the flash loans and kept the remaining assets (mostly ETH and stablecoins).
|
|
31
|
+
|
|
32
|
+
## Impact
|
|
33
|
+
- **Loss**: ~$182M
|
|
34
|
+
- **Protocol**: Beanstalk Farms
|
|
35
|
+
- **Chain**: Ethereum
|
|
36
|
+
- **Date**: 2022-04-17
|
|
37
|
+
|
|
38
|
+
## Key Transactions
|
|
39
|
+
- Attack tx: `0xcd314c6351513518c37cba34ba8225939f8f5787a0a0d958999cc468992275d6`
|
|
40
|
+
|
|
41
|
+
## Detection Heuristics
|
|
42
|
+
- Pattern 1: Governance systems where voting power can be acquired and used within the same transaction (vulnerable to flash loans).
|
|
43
|
+
- Pattern 2: Lack of a delay between proposal submission, voting, and execution.
|
|
44
|
+
|
|
45
|
+
## Remediation
|
|
46
|
+
- Fix 1: Implement a "snapshot" mechanism for voting power, where power is determined by balances at a previous block.
|
|
47
|
+
- Fix 2: Introduce a mandatory delay (e.g., 2-3 days) between proposal submission and the start of voting, and another delay before execution.
|
|
48
|
+
- Fix 3: Prevent flash-loaned assets from being used to gain governance rights (e.g., by checking if the balance was acquired in the same block).
|
|
49
|
+
|
|
50
|
+
## References
|
|
51
|
+
- [rekt.news/beanstalk-rekt/](https://rekt.news/beanstalk-rekt/)
|
|
52
|
+
- [bean.money/blog/2022-04-18-post-mortem-of-the-beanstalk-exploit](https://bean.money/blog/2022-04-18-post-mortem-of-the-beanstalk-exploit)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bzx-flash-loan
|
|
3
|
+
description: "Case study of the 2020 bZx exploits: oracle manipulation via flash loans draining ~$1M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/bzx-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: 'KyberNetworkProxy|UniswapV2Router'
|
|
10
|
+
severity: "Medium"
|
|
11
|
+
description: "Detects usage of DEX routers which might be used as price oracles."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# bZx Flash Loan Exploits (2020)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In February 2020, bZx was hit by two separate flash loan attacks within days. The first attack involved a complex sequence of trades to manipulate the price of WBTC on Kyber, while the second attack manipulated the sUSD price on Kyber using a flash loan from bZx itself. Total losses were approximately $1M.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The primary vulnerability was bZx's reliance on a single on-chain liquidity source (Kyber) as a price oracle. By using flash loans to execute large trades on Kyber, the attacker could significantly move the price, allowing them to take out undercollateralized loans or execute profitable liquidations on bZx.
|
|
23
|
+
|
|
24
|
+
## Attack Flow (First Attack)
|
|
25
|
+
1. Attacker took a flash loan of 10,000 ETH from dYdX.
|
|
26
|
+
2. Attacker deposited 5,500 ETH to Compound to borrow 112 WBTC.
|
|
27
|
+
3. Attacker deposited 1,300 ETH to bZx to open a 5x short position on ETH/BTC.
|
|
28
|
+
4. bZx executed the short by swapping ETH for WBTC on Kyber, which routed to Uniswap.
|
|
29
|
+
5. The large trade on Uniswap caused massive slippage, driving up the WBTC price.
|
|
30
|
+
6. Attacker sold the 112 WBTC borrowed from Compound back into the manipulated market for a huge profit.
|
|
31
|
+
7. Attacker repaid the dYdX flash loan.
|
|
32
|
+
|
|
33
|
+
## Impact
|
|
34
|
+
- **Loss**: ~$1M
|
|
35
|
+
- **Protocol**: bZx (Fulcrum/Torque)
|
|
36
|
+
- **Chain**: Ethereum
|
|
37
|
+
- **Date**: 2020-02-15 (First), 2020-02-18 (Second)
|
|
38
|
+
|
|
39
|
+
## Key Transactions
|
|
40
|
+
- First Attack tx: `0xb5c8bd9430b6cc87a0e2fe110ece6bf527fa4f170a4bc8cd032f768fc5219838`
|
|
41
|
+
- Second Attack tx: `0x762881dda4f35930d15524a4413fde45bc75096f0a7a495caeac6197b928e934`
|
|
42
|
+
|
|
43
|
+
## Detection Heuristics
|
|
44
|
+
- Pattern 1: Use of low-liquidity DEX pools as the sole price oracle for lending or margin trading.
|
|
45
|
+
- Pattern 2: Lack of slippage checks or price deviation checks against external oracles (like Chainlink).
|
|
46
|
+
|
|
47
|
+
## Remediation
|
|
48
|
+
- Fix 1: Use decentralized, aggregate oracles like Chainlink or Time-Weighted Average Prices (TWAP) from Uniswap V2+.
|
|
49
|
+
- Fix 2: Implement circuit breakers or maximum slippage limits for large trades.
|
|
50
|
+
|
|
51
|
+
## References
|
|
52
|
+
- [rekt.news/bzx-rekt/](https://rekt.news/bzx-rekt/)
|
|
53
|
+
- [bzx.network/blog/post-mortem-eth-btc-margin-tokens-exploit](https://bzx.network/blog/post-mortem-eth-btc-margin-tokens-exploit)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cream-finance
|
|
3
|
+
description: "Case study of the 2021 Cream Finance exploit: flash loan + oracle manipulation draining ~$130M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/cream-rekt-2/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: 'yUSD|yETH'
|
|
10
|
+
severity: "Medium"
|
|
11
|
+
description: "Detects usage of Yearn vault tokens which can have complex pricing mechanisms vulnerable to manipulation."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# Cream Finance (2021)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In October 2021, Cream Finance was exploited for approximately $130 million. The attacker used a complex flash loan attack to manipulate the price of Yearn's yUSD vault tokens, which were used as collateral on Cream. By inflating the value of yUSD, the attacker was able to borrow almost all other assets available on the platform.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The vulnerability lay in how Cream Finance calculated the price of Yearn vault tokens (yUSD). The price was derived from the total assets in the Yearn vault divided by the total supply of vault shares. The attacker used flash loans to deposit a massive amount of assets into the Yearn vault, which temporarily inflated the "price per share" used by Cream's oracle.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. Attacker took a massive flash loan of 500M DAI and other assets from MakerDAO and Aave.
|
|
26
|
+
2. Attacker deposited the DAI into Yearn's yUSD vault to receive yUSD tokens.
|
|
27
|
+
3. Attacker then deposited the yUSD into Cream Finance as collateral.
|
|
28
|
+
4. Attacker used more flash-loaned assets to further manipulate the Yearn vault's internal state, significantly increasing the reported value of yUSD on Cream.
|
|
29
|
+
5. With the inflated collateral value, the attacker borrowed almost all liquid assets from Cream's lending pools (ETH, WBTC, stablecoins).
|
|
30
|
+
6. Attacker repaid the flash loans and kept the borrowed assets.
|
|
31
|
+
|
|
32
|
+
## Impact
|
|
33
|
+
- **Loss**: ~$130M
|
|
34
|
+
- **Protocol**: Cream Finance
|
|
35
|
+
- **Chain**: Ethereum
|
|
36
|
+
- **Date**: 2021-10-27
|
|
37
|
+
|
|
38
|
+
## Key Transactions
|
|
39
|
+
- Attack tx: `0x0fe2588608f3588c4a273c63e47ae7793c920909623d9d55666e082059d3c7df`
|
|
40
|
+
|
|
41
|
+
## Detection Heuristics
|
|
42
|
+
- Pattern 1: Using vault share prices (like `pricePerShare`) as an oracle without accounting for potential manipulation of the underlying vault's reserves.
|
|
43
|
+
- Pattern 2: Lack of caps on how much a single asset can be used as collateral, especially for complex derivative tokens.
|
|
44
|
+
|
|
45
|
+
## Remediation
|
|
46
|
+
- Fix 1: Use more robust oracles that are resistant to instantaneous reserve manipulation (e.g., Chainlink or TWAP).
|
|
47
|
+
- Fix 2: Implement collateral caps and borrow limits to prevent a single exploit from draining the entire protocol.
|
|
48
|
+
- Fix 3: Add a delay or "sanity check" when the price of a collateral asset changes significantly within a short period.
|
|
49
|
+
|
|
50
|
+
## References
|
|
51
|
+
- [rekt.news/cream-rekt-2/](https://rekt.news/cream-rekt-2/)
|
|
52
|
+
- [medium.com/cream-finance/c-r-e-a-m-finance-post-mortem-october-27-2021-d5a411f3f87a](https://medium.com/cream-finance/c-r-e-a-m-finance-post-mortem-october-27-2021-d5a411f3f87a)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: curve-reentrancy
|
|
3
|
+
description: "Case study of the 2023 Curve reentrancy exploit: Vyper compiler bug draining ~$70M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/curve-lp-rekt-vyper-reentrancy/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: '@nonreentrant'
|
|
10
|
+
severity: "High"
|
|
11
|
+
description: "Detects Vyper's nonreentrant decorator. In certain compiler versions (0.2.15, 0.2.16, 0.3.0), this was broken for cross-function reentrancy."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# Curve Reentrancy (2023)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In July 2023, several Curve Finance liquidity pools (alETH, msETH, pETH) were exploited for approximately $70 million. Unlike most reentrancy attacks caused by developer error, this was caused by a bug in the Vyper compiler (versions 0.2.15, 0.2.16, and 0.3.0) that failed to properly implement reentrancy guards.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The vulnerability was a compiler-level bug in Vyper's `@nonreentrant` decorator. In the affected versions, the compiler used the same storage slot for reentrancy locks across different functions if they were in the same "reentrancy group", but it failed to correctly handle the lock state in certain scenarios involving cross-function calls. This allowed an attacker to re-enter a contract through a different function even if both were marked `@nonreentrant`.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. Attacker identified Curve pools using vulnerable Vyper versions (specifically those with `add_liquidity` and `remove_liquidity` functions).
|
|
26
|
+
2. Attacker called `add_liquidity` to deposit assets.
|
|
27
|
+
3. During the execution of `add_liquidity`, the contract made an external call (e.g., to a token's `transfer` or `fallback` function).
|
|
28
|
+
4. The attacker's malicious contract re-entered the Curve pool by calling `remove_liquidity`.
|
|
29
|
+
5. Because the reentrancy guard was broken at the compiler level, the second call was allowed to proceed before the first call's state updates (like updating the pool's total supply) were finalized.
|
|
30
|
+
6. This allowed the attacker to withdraw more assets than they were entitled to.
|
|
31
|
+
|
|
32
|
+
## Impact
|
|
33
|
+
- **Loss**: ~$70M
|
|
34
|
+
- **Protocol**: Curve Finance
|
|
35
|
+
- **Chain**: Ethereum
|
|
36
|
+
- **Date**: 2023-07-30
|
|
37
|
+
|
|
38
|
+
## Key Transactions
|
|
39
|
+
- Attack tx (pETH pool): `0xa84aa0650c3e6f849339384388e1a769a540003ade07ba379c2d3efc4fb7ca7d`
|
|
40
|
+
|
|
41
|
+
## Detection Heuristics
|
|
42
|
+
- Pattern 1: Use of Vyper compiler versions 0.2.15, 0.2.16, or 0.3.0.
|
|
43
|
+
- Pattern 2: Contracts with multiple functions using the same reentrancy lock key.
|
|
44
|
+
|
|
45
|
+
## Remediation
|
|
46
|
+
- Fix 1: Upgrade to a patched version of the Vyper compiler (0.3.1 or later).
|
|
47
|
+
- Fix 2: Manually implement reentrancy guards using storage variables if the compiler version cannot be changed.
|
|
48
|
+
- Fix 3: Conduct thorough audits that include checking the underlying compiler and infrastructure vulnerabilities.
|
|
49
|
+
|
|
50
|
+
## References
|
|
51
|
+
- [rekt.news/curve-lp-rekt-vyper-reentrancy/](https://rekt.news/curve-lp-rekt-vyper-reentrancy/)
|
|
52
|
+
- [hackmd.io/@vyperlang/H1No9_h_h](https://hackmd.io/@vyperlang/H1No9_h_h)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dao-hack
|
|
3
|
+
description: "Case study of the 2016 DAO hack: reentrancy exploit draining ~$60M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/dao-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: '\.call\{value:.*\}\(.*\);'
|
|
10
|
+
severity: "High"
|
|
11
|
+
description: "Detects low-level calls that may be vulnerable to reentrancy if state is updated after the call."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# DAO Hack (2016)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
The DAO was a decentralized autonomous organization launched in 2016 on the Ethereum blockchain. It was designed to operate as a venture capital fund for the crypto space. In June 2016, an attacker exploited a reentrancy vulnerability in the DAO's smart contract, draining approximately 3.6 million ETH, worth about $60 million at the time.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The vulnerability was a classic reentrancy bug. The `splitDAO` function allowed a member to withdraw their ETH and receive "Child DAO" tokens. The contract sent ETH to the user using a low-level `.call()` before updating the user's balance. This allowed the attacker to recursively call the `splitDAO` function from their malicious contract's fallback function before the first call finished, effectively draining the contract.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. The attacker created a malicious contract and funded it with DAO tokens.
|
|
26
|
+
2. The attacker called the `splitDAO` function.
|
|
27
|
+
3. The DAO contract sent ETH to the attacker's contract via a low-level call.
|
|
28
|
+
4. The attacker's fallback function triggered another call to `splitDAO`.
|
|
29
|
+
5. Steps 3 and 4 repeated recursively until the gas limit was reached or the contract was drained.
|
|
30
|
+
6. The state update (reducing the attacker's balance) only happened after the recursive calls finished, which was too late.
|
|
31
|
+
|
|
32
|
+
## Impact
|
|
33
|
+
- **Loss**: ~$60M (3.6M ETH)
|
|
34
|
+
- **Protocol**: The DAO
|
|
35
|
+
- **Chain**: Ethereum
|
|
36
|
+
- **Date**: 2016-06-17
|
|
37
|
+
|
|
38
|
+
## Key Transactions
|
|
39
|
+
- Attack tx: `0x0eb3f4d006903f621f048358878b2ad9046f00d28e5540fa24644433252170e4`
|
|
40
|
+
|
|
41
|
+
## Detection Heuristics
|
|
42
|
+
- Pattern 1: Low-level `.call()` used for ETH transfers without a reentrancy guard.
|
|
43
|
+
- Pattern 2: State variables (like balances) updated after an external call.
|
|
44
|
+
|
|
45
|
+
## Remediation
|
|
46
|
+
- Fix 1: Use the Checks-Effects-Interactions pattern. Update state before making external calls.
|
|
47
|
+
- Fix 2: Implement a reentrancy guard (e.g., OpenZeppelin's `ReentrancyGuard`).
|
|
48
|
+
|
|
49
|
+
## References
|
|
50
|
+
- [rekt.news/dao-rekt/](https://rekt.news/dao-rekt/)
|
|
51
|
+
- [blog.slock.it/the-history-of-the-dao-628d50257c3d](https://blog.slock.it/the-history-of-the-dao-628d50257c3d)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: euler-finance
|
|
3
|
+
description: "Case study of the 2023 Euler Finance exploit: donation attack draining ~$197M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/euler-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: 'donateToReserves'
|
|
10
|
+
severity: "High"
|
|
11
|
+
description: "Detects donation functions that might allow a user to intentionally make their position underwater to trigger liquidations."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# Euler Finance (2023)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In March 2023, Euler Finance, a non-custodial lending protocol, was exploited for approximately $197 million. The attacker used a "donation attack" where they intentionally made their own position underwater by donating funds to the protocol's reserves, allowing them to liquidate themselves and profit from the protocol's bad debt handling.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The vulnerability was in the `donateToReserves` function of the EToken contract. This function allowed a user to donate their EToken balance to the protocol's reserves. However, it did not check if the donation would make the user's position insolvent. By donating a large amount of collateral while having a large debt, the attacker could make their position underwater and then use a separate account to liquidate the position at a massive discount.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. Attacker took a flash loan of 30M DAI from Aave.
|
|
26
|
+
2. Attacker deposited 20M DAI into Euler to receive eDAI.
|
|
27
|
+
3. Attacker leveraged their position by minting 200M dDAI (debt) and 195M eDAI (collateral).
|
|
28
|
+
4. Attacker called `donateToReserves` with 100M eDAI. This reduced their collateral but kept their debt the same, making the position heavily underwater.
|
|
29
|
+
5. Attacker used a second account to liquidate the first account. Due to the way Euler's liquidation worked, the liquidator received the remaining eDAI at a massive discount, while the protocol was left with bad debt.
|
|
30
|
+
6. Attacker repeated this for other assets (wBTC, wETH, stETH).
|
|
31
|
+
7. Attacker repaid the flash loan and kept the profit.
|
|
32
|
+
|
|
33
|
+
## Impact
|
|
34
|
+
- **Loss**: ~$197M
|
|
35
|
+
- **Protocol**: Euler Finance
|
|
36
|
+
- **Chain**: Ethereum
|
|
37
|
+
- **Date**: 2023-03-13
|
|
38
|
+
|
|
39
|
+
## Key Transactions
|
|
40
|
+
- Attack tx (DAI): `0xc310a0affe2169d1f6feec1c63dbc7f7c62a88bf44e7906e2bc6445e10086615`
|
|
41
|
+
|
|
42
|
+
## Detection Heuristics
|
|
43
|
+
- Pattern 1: Functions that allow users to reduce their collateral (e.g., via donation or transfer) without checking their health factor or solvency.
|
|
44
|
+
- Pattern 2: Liquidation logic that doesn't properly account for "donated" or "burned" collateral.
|
|
45
|
+
|
|
46
|
+
## Remediation
|
|
47
|
+
- Fix 1: Add a health factor check to the `donateToReserves` function to ensure the user remains solvent after the donation.
|
|
48
|
+
- Fix 2: Implement stricter checks on liquidation bonuses and ensure that the protocol's reserves are not used to subsidize malicious liquidations.
|
|
49
|
+
|
|
50
|
+
## References
|
|
51
|
+
- [rekt.news/euler-rekt/](https://rekt.news/euler-rekt/)
|
|
52
|
+
- [euler.finance/blog/euler-vault-kit-post-mortem](https://www.euler.finance/blog/euler-vault-kit-post-mortem)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harvest-finance
|
|
3
|
+
description: "Case study of the 2020 Harvest Finance exploit: flash loan + price manipulation draining ~$34M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/harvest-finance-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: 'getPricePerFullShare'
|
|
10
|
+
severity: "Medium"
|
|
11
|
+
description: "Detects usage of share price functions which can be manipulated by large trades in underlying pools."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# Harvest Finance (2020)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In October 2020, Harvest Finance was exploited for approximately $34 million. The attacker used flash loans to manipulate the price of stablecoins (USDC and USDT) within Curve Finance pools, which Harvest used to calculate the value of its vault shares.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
Harvest Finance vaults calculated the value of their shares based on the "virtual price" of assets in Curve pools. By using a flash loan to execute a massive swap in a Curve pool, the attacker could temporarily depress the price of an asset. They then deposited that asset into Harvest at the depressed price, swapped back in Curve to restore the price, and withdrew from Harvest at the higher price.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. Attacker took a flash loan of 50M USDC and 17.3M USDT from Uniswap V2.
|
|
26
|
+
2. Attacker swapped 11.4M USDC for USDT on Curve's Y pool, pushing down the USDC price.
|
|
27
|
+
3. Attacker deposited 60.6M USDC into the Harvest fUSDC vault. Because the USDC price was manipulated downwards, the attacker received more fUSDC shares than they should have.
|
|
28
|
+
4. Attacker swapped the USDT back for USDC on Curve, restoring the price.
|
|
29
|
+
5. Attacker withdrew USDC from the Harvest vault. Since the price was now higher, their shares were worth more USDC than they deposited.
|
|
30
|
+
6. Attacker repeated this process multiple times.
|
|
31
|
+
7. Attacker repaid the flash loan and walked away with the profit.
|
|
32
|
+
|
|
33
|
+
## Impact
|
|
34
|
+
- **Loss**: ~$34M
|
|
35
|
+
- **Protocol**: Harvest Finance
|
|
36
|
+
- **Chain**: Ethereum
|
|
37
|
+
- **Date**: 2020-10-26
|
|
38
|
+
|
|
39
|
+
## Key Transactions
|
|
40
|
+
- Attack tx: `0x35f8d2f572fceaac9288e5632737885a062dd0c8587ce9044329942b694a9974`
|
|
41
|
+
|
|
42
|
+
## Detection Heuristics
|
|
43
|
+
- Pattern 1: Calculating share value or collateral value based on instantaneous on-chain prices from a single pool.
|
|
44
|
+
- Pattern 2: Lack of slippage protection or "sanity checks" against a more robust oracle when depositing or withdrawing from vaults.
|
|
45
|
+
|
|
46
|
+
## Remediation
|
|
47
|
+
- Fix 1: Use a decentralized oracle (like Chainlink) or a TWAP for asset valuation.
|
|
48
|
+
- Fix 2: Implement a "slippage" or "premium" check that prevents deposits/withdrawals when the pool price deviates significantly from the oracle price.
|
|
49
|
+
|
|
50
|
+
## References
|
|
51
|
+
- [rekt.news/harvest-finance-rekt/](https://rekt.news/harvest-finance-rekt/)
|
|
52
|
+
- [medium.com/harvest-finance/harvest-flashloan-economic-attack-post-mortem-3cf900d65bc6](https://medium.com/harvest-finance/harvest-flashloan-economic-attack-post-mortem-3cf900d65bc6)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: level-finance
|
|
3
|
+
description: "Case study of the 2023 Level Finance exploit: referral code reentrancy draining ~$1.1M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/level-finance-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: 'claimMultiple'
|
|
10
|
+
severity: "High"
|
|
11
|
+
description: "Detects functions that allow multiple claims in a single transaction. Must be checked for reentrancy if they involve external calls."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# Level Finance (2023)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In May 2023, Level Finance, a decentralized perpetual exchange on BNB Chain, was exploited for approximately $1.1 million. The attacker exploited a reentrancy vulnerability in the protocol's referral contract, specifically within the `claimMultiple` function, allowing them to claim referral rewards multiple times in a single transaction.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The vulnerability was in the `LevelReferralController` contract. The `claimMultiple` function allowed users to claim rewards for multiple referral epochs. However, the function did not follow the Checks-Effects-Interactions pattern and lacked a reentrancy guard. The contract sent rewards to the user before updating the `isClaimed` status for the epoch, allowing the attacker to re-enter the function and claim the same rewards repeatedly.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. Attacker created multiple referral accounts and generated referral rewards.
|
|
26
|
+
2. Attacker called the `claimMultiple` function with a list of epoch IDs.
|
|
27
|
+
3. The contract calculated the rewards and sent them to the attacker's malicious contract.
|
|
28
|
+
4. The attacker's fallback function triggered another call to `claimMultiple` with the same epoch IDs.
|
|
29
|
+
5. Because the `isClaimed` status was only updated after the loop finished, the second call (and subsequent recursive calls) succeeded.
|
|
30
|
+
6. Attacker drained approximately 214,000 LVL tokens and swapped them for 3,345 BNB.
|
|
31
|
+
|
|
32
|
+
## Impact
|
|
33
|
+
- **Loss**: ~$1.1M
|
|
34
|
+
- **Protocol**: Level Finance
|
|
35
|
+
- **Chain**: BNB Chain
|
|
36
|
+
- **Date**: 2023-05-01
|
|
37
|
+
|
|
38
|
+
## Key Transactions
|
|
39
|
+
- Attack tx: `0xe18396571315154179da08573f38039c50f8c46653302f9c449e10ba575606f5`
|
|
40
|
+
|
|
41
|
+
## Detection Heuristics
|
|
42
|
+
- Pattern 1: Reward claiming functions that iterate over a list and make external calls within the loop before updating the "claimed" status.
|
|
43
|
+
- Pattern 2: Lack of reentrancy guards on functions that handle token transfers or sensitive state updates.
|
|
44
|
+
|
|
45
|
+
## Remediation
|
|
46
|
+
- Fix 1: Implement a reentrancy guard (`nonReentrant` modifier) on the `claimMultiple` function.
|
|
47
|
+
- Fix 2: Use the Checks-Effects-Interactions pattern. Update the `isClaimed` status for each epoch *before* sending the rewards.
|
|
48
|
+
|
|
49
|
+
## References
|
|
50
|
+
- [rekt.news/level-finance-rekt/](https://rekt.news/level-finance-rekt/)
|
|
51
|
+
- [twitter.com/Level__Finance/status/1653035345610817536](https://twitter.com/Level__Finance/status/1653035345610817536)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mango-markets
|
|
3
|
+
description: "Case study of the 2022 Mango Markets exploit: oracle price manipulation draining ~$114M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/mango-markets-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: 'MNGO'
|
|
10
|
+
severity: "Low"
|
|
11
|
+
description: "Detects usage of the MNGO token. Highlights the risk of using low-liquidity governance tokens as collateral."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# Mango Markets (2022)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In October 2022, Mango Markets, a decentralized exchange on Solana, was exploited for approximately $114 million. The attacker used a large amount of capital to manipulate the price of the MNGO token on the platform's own order book, which was used as the price oracle for collateral valuation.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The vulnerability was the protocol's reliance on its own low-liquidity internal markets as a price oracle for its native token (MNGO). By wash trading MNGO against USDC, the attacker was able to artificially inflate the price of MNGO. Because Mango used this manipulated price to determine how much a user could borrow, the attacker was able to take out massive loans of other assets (USDC, SOL, BTC, etc.) against their "valuable" MNGO collateral.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. Attacker funded two separate accounts with 5M USDC each.
|
|
26
|
+
2. Account A placed a large sell order for MNGO perps at a high price.
|
|
27
|
+
3. Account B placed a large buy order for MNGO perps, matching Account A's order.
|
|
28
|
+
4. This wash trade significantly moved the MNGO price on the Mango order book.
|
|
29
|
+
5. The internal oracle updated the MNGO price based on these trades, inflating it by over 2,000%.
|
|
30
|
+
6. With the inflated MNGO collateral value, Account B borrowed $114M worth of various assets from the Mango treasury.
|
|
31
|
+
7. The attacker then proposed a governance settlement to return some funds in exchange for no criminal prosecution (which was later rejected by law enforcement).
|
|
32
|
+
|
|
33
|
+
## Impact
|
|
34
|
+
- **Loss**: ~$114M
|
|
35
|
+
- **Protocol**: Mango Markets
|
|
36
|
+
- **Chain**: Solana
|
|
37
|
+
- **Date**: 2022-10-11
|
|
38
|
+
|
|
39
|
+
## Key Transactions
|
|
40
|
+
- Attack tx (Example): `599986Yfs4S6996Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9Yv9`
|
|
41
|
+
|
|
42
|
+
## Detection Heuristics
|
|
43
|
+
- Pattern 1: Using internal, low-liquidity markets as the primary price oracle for collateral.
|
|
44
|
+
- Pattern 2: Lack of caps on borrowing against highly volatile or manipulatable assets.
|
|
45
|
+
|
|
46
|
+
## Remediation
|
|
47
|
+
- Fix 1: Use external, aggregate oracles (like Pyth or Chainlink) that incorporate liquidity from multiple high-volume exchanges.
|
|
48
|
+
- Fix 2: Implement "oracle confidence intervals" or "sanity checks" that ignore price spikes that aren't reflected in broader markets.
|
|
49
|
+
- Fix 3: Set strict borrow limits and higher collateral requirements for native governance tokens.
|
|
50
|
+
|
|
51
|
+
## References
|
|
52
|
+
- [rekt.news/mango-markets-rekt/](https://rekt.news/mango-markets-rekt/)
|
|
53
|
+
- [mango.markets/blog/post-mortem-october-exploit](https://mango.markets/blog/post-mortem-october-exploit)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nomad-bridge
|
|
3
|
+
description: "Case study of the 2022 Nomad Bridge exploit: initialization bug draining ~$190M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/nomad-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: '0x0000000000000000000000000000000000000000000000000000000000000000'
|
|
10
|
+
severity: "High"
|
|
11
|
+
description: "Detects usage of the zero hash as a trusted value, which can be dangerous if it's the default state of an uninitialized mapping."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# Nomad Bridge (2022)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In August 2022, the Nomad bridge was drained of approximately $190 million in a "decentralized robbery." A routine upgrade accidentally initialized the bridge's trusted root to a zero hash (`0x00`), allowing anyone to bypass message verification by providing a message that hashed to a value already present in the uninitialized mapping.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The vulnerability was introduced during a contract upgrade. The `Replica` contract's `confirmAt` mapping was intended to store the time at which a message root was confirmed. The upgrade set the default "trusted" root to `0x00`. Because uninitialized storage in Solidity is `0`, any message with a root of `0x00` was automatically considered "confirmed" by the contract. This allowed users to submit withdrawal messages with arbitrary data that would be executed without valid signatures.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. Attacker noticed that the `Replica` contract accepted messages with a root of `0x00`.
|
|
26
|
+
2. Attacker crafted a message to withdraw funds from the bridge.
|
|
27
|
+
3. Attacker submitted the message to the `process` function.
|
|
28
|
+
4. The contract checked if the message's root was confirmed. Since the root was `0x00` and the mapping returned `0` (or a value that passed the check), the message was processed.
|
|
29
|
+
5. Once the first attack was public, hundreds of other users (copycats) simply copied the transaction data, changed the recipient address, and drained the remaining funds.
|
|
30
|
+
|
|
31
|
+
## Impact
|
|
32
|
+
- **Loss**: ~$190M
|
|
33
|
+
- **Protocol**: Nomad Bridge
|
|
34
|
+
- **Chain**: Ethereum / Moonbeam / Evmos / etc.
|
|
35
|
+
- **Date**: 2022-08-01
|
|
36
|
+
|
|
37
|
+
## Key Transactions
|
|
38
|
+
- First Attack tx: `0xa5ce309047a92177ad43c03f1f13a87339e38c89509cf5564d79775c4456cf92`
|
|
39
|
+
|
|
40
|
+
## Detection Heuristics
|
|
41
|
+
- Pattern 1: Trusting a zero value (`0x00` or `0`) in a mapping that is also the default state for uninitialized entries.
|
|
42
|
+
- Pattern 2: Lack of explicit checks to ensure that a root or hash is not the zero value before processing sensitive operations.
|
|
43
|
+
|
|
44
|
+
## Remediation
|
|
45
|
+
- Fix 1: Explicitly initialize trusted roots to a non-zero value or use a separate boolean mapping to track confirmation.
|
|
46
|
+
- Fix 2: Add a `require(root != bytes32(0))` check in the message verification logic.
|
|
47
|
+
- Fix 3: Implement more rigorous testing for contract upgrades, specifically checking the state of critical storage variables.
|
|
48
|
+
|
|
49
|
+
## References
|
|
50
|
+
- [rekt.news/nomad-rekt/](https://rekt.news/nomad-rekt/)
|
|
51
|
+
- [medium.com/nomad-xyz-blog/nomad-bridge-hack-post-mortem-e6f630cf3b7f](https://medium.com/nomad-xyz-blog/nomad-bridge-hack-post-mortem-e6f630cf3b7f)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: parity-multisig
|
|
3
|
+
description: "Case study of the 2017 Parity Multisig Freeze: delegatecall + self-destruct exploit freezing ~$150M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/parity-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: 'delegatecall\(.*\)'
|
|
10
|
+
severity: "High"
|
|
11
|
+
description: "Detects use of delegatecall, which can be dangerous if the target contract is not trusted or can be modified."
|
|
12
|
+
- regex: 'selfdestruct\(.*\)'
|
|
13
|
+
severity: "High"
|
|
14
|
+
description: "Detects use of selfdestruct, which can be used to destroy a contract and freeze funds if not properly protected."
|
|
15
|
+
---
|
|
16
|
+
<!-- Source: rekt.news (CC0) -->
|
|
17
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
18
|
+
|
|
19
|
+
# Parity Multisig Freeze (2017)
|
|
20
|
+
|
|
21
|
+
## Overview
|
|
22
|
+
In November 2017, a user accidentally triggered a vulnerability in the Parity Multisig wallet library contract. By calling an uninitialized `initWallet` function, the user became the owner of the library contract and subsequently called `kill()`, which executed `selfdestruct`. This froze approximately 513,000 ETH (worth ~$150M at the time) across 587 wallets that depended on this library.
|
|
23
|
+
|
|
24
|
+
## Root Cause
|
|
25
|
+
The Parity Multisig wallets used `delegatecall` to execute logic from a shared library contract. However, the library contract itself was not initialized. This allowed any user to call the `initWallet` function on the library contract directly, making them the owner of the library. Once they were the owner, they could call the `kill` function, which contained a `selfdestruct` instruction.
|
|
26
|
+
|
|
27
|
+
## Attack Flow
|
|
28
|
+
1. A user (devops199) found the uninitialized library contract.
|
|
29
|
+
2. The user called `initWallet()` on the library contract, becoming its owner.
|
|
30
|
+
3. The user then called `kill()` on the library contract.
|
|
31
|
+
4. The library contract executed `selfdestruct`, removing its code from the blockchain.
|
|
32
|
+
5. All multisig wallets that used `delegatecall` to this library now had no logic to execute, effectively freezing all funds held in them.
|
|
33
|
+
|
|
34
|
+
## Impact
|
|
35
|
+
- **Loss**: ~$150M (513k ETH)
|
|
36
|
+
- **Protocol**: Parity Multisig
|
|
37
|
+
- **Chain**: Ethereum
|
|
38
|
+
- **Date**: 2017-11-06
|
|
39
|
+
|
|
40
|
+
## Key Transactions
|
|
41
|
+
- Initialization tx: `0x05f5c113c130f928d4d0d261046c5511846909b77060ef6568bf9158ad312a06`
|
|
42
|
+
- Kill tx: `0x47f7cff3ad8733831a0e273108ef239bb0d0657da3a4279b1d17ac2616a12487`
|
|
43
|
+
|
|
44
|
+
## Detection Heuristics
|
|
45
|
+
- Pattern 1: Uninitialized library contracts that contain sensitive functions like `selfdestruct` or `init`.
|
|
46
|
+
- Pattern 2: Use of `delegatecall` to a contract that can be destroyed or modified by unauthorized users.
|
|
47
|
+
|
|
48
|
+
## Remediation
|
|
49
|
+
- Fix 1: Initialize library contracts during deployment or use a constructor to disable initialization functions.
|
|
50
|
+
- Fix 2: Avoid using `selfdestruct` in library contracts.
|
|
51
|
+
- Fix 3: Use static libraries or ensure the target of `delegatecall` is immutable and properly initialized.
|
|
52
|
+
|
|
53
|
+
## References
|
|
54
|
+
- [rekt.news/parity-rekt/](https://rekt.news/parity-rekt/)
|
|
55
|
+
- [paritytech.io/blog/security-alert-heavy-update/](https://www.parity.io/blog/security-alert-heavy-update/)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: poly-network
|
|
3
|
+
description: "Case study of the 2021 Poly Network exploit: cross-chain relay manipulation draining ~$600M"
|
|
4
|
+
category: reference
|
|
5
|
+
source_url: "https://rekt.news/polynetwork-rekt/"
|
|
6
|
+
source_license: "CC0"
|
|
7
|
+
imported_at: "2025-02-20T00:00:00Z"
|
|
8
|
+
detection_rules:
|
|
9
|
+
- regex: 'putCurEpochConPubKeyBytes'
|
|
10
|
+
severity: "High"
|
|
11
|
+
description: "Detects functions that can modify the public keys of cross-chain relayers/keepers."
|
|
12
|
+
---
|
|
13
|
+
<!-- Source: rekt.news (CC0) -->
|
|
14
|
+
<!-- Source: SunWeb3Sec/DeFiHackLabs (Reference) -->
|
|
15
|
+
|
|
16
|
+
# Poly Network (2021)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
In August 2021, Poly Network, a cross-chain interoperability protocol, was exploited for approximately $611 million across Ethereum, Binance Smart Chain, and Polygon. The attacker was able to manipulate the protocol's "keeper" role, allowing them to sign and execute arbitrary cross-chain transactions.
|
|
20
|
+
|
|
21
|
+
## Root Cause
|
|
22
|
+
The vulnerability was in the `EthCrossChainManager` contract. The contract had a function `crossChain` that could call any contract on the target chain. The attacker used this to call the `EthCrossChainData` contract's `putCurEpochConPubKeyBytes` function. This function was intended to update the public keys of the "keepers" (the entities that sign cross-chain messages). Because the `EthCrossChainManager` was the owner of the `EthCrossChainData` contract, the call was authorized, allowing the attacker to replace the official keeper keys with their own.
|
|
23
|
+
|
|
24
|
+
## Attack Flow
|
|
25
|
+
1. Attacker crafted a cross-chain message on a source chain (e.g., Ontology).
|
|
26
|
+
2. The message was designed to trigger a call to `putCurEpochConPubKeyBytes` on the target chain (Ethereum/BSC/Polygon).
|
|
27
|
+
3. The `EthCrossChainManager` received the message and, because it was the owner of the data contract, executed the call.
|
|
28
|
+
4. The attacker's public key was now registered as the only valid keeper key.
|
|
29
|
+
5. The attacker then crafted and signed withdrawal transactions for the bridge's assets using their own key.
|
|
30
|
+
6. The bridge accepted these transactions as valid and released the funds.
|
|
31
|
+
|
|
32
|
+
## Impact
|
|
33
|
+
- **Loss**: ~$611M (Most was later returned by the attacker)
|
|
34
|
+
- **Protocol**: Poly Network
|
|
35
|
+
- **Chain**: Ethereum, BSC, Polygon
|
|
36
|
+
- **Date**: 2021-08-10
|
|
37
|
+
|
|
38
|
+
## Key Transactions
|
|
39
|
+
- Attack tx (Ethereum): `0xb1f3535b698f3a0917a219673e7c0e1501c35f9bb8a2811b7a781363bd23c228`
|
|
40
|
+
|
|
41
|
+
## Detection Heuristics
|
|
42
|
+
- Pattern 1: Cross-chain managers that can call arbitrary functions on internal data or configuration contracts.
|
|
43
|
+
- Pattern 2: Lack of strict access control on functions that modify critical system roles (like keepers or validators).
|
|
44
|
+
|
|
45
|
+
## Remediation
|
|
46
|
+
- Fix 1: Implement a whitelist of allowed functions that can be called via cross-chain messages.
|
|
47
|
+
- Fix 2: Ensure that critical configuration functions (like updating keeper keys) require multi-signature authorization or a time-lock, and cannot be triggered by a single cross-chain call.
|
|
48
|
+
|
|
49
|
+
## References
|
|
50
|
+
- [rekt.news/polynetwork-rekt/](https://rekt.news/polynetwork-rekt/)
|
|
51
|
+
- [slowmist.medium.com/the-analysis-and-q-a-of-poly-network-hack-8112a353e439](https://slowmist.medium.com/the-analysis-and-q-a-of-poly-network-hack-8112a353e439)
|