Skip to content

Instantly share code, notes, and snippets.

View CharaD7's full-sized avatar
🏠
Working from home

Joy Ayitey CharaD7

🏠
Working from home
View GitHub Profile
@CharaD7
CharaD7 / IndexOverflow.t.sol
Last active August 18, 2026 09:58
Aave RewardsDistributor INDEX_OVERFLOW: dust-supply permanently bricks an incentivized reserve's supply side (deployed INCENTIVES_IMPL 0x0ee554F6)
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import {Test, console2} from "forge-std/Test.sol";
/// Minimal, faithful reproduction of the DEPLOYED Aave RewardsDistributor index math
/// (aave-v3-periphery RewardsDistributor, mainnet INCENTIVES_IMPL 0x0ee554F6, Sourcify
/// exact-match verified). The deployed _getAssetIndex is:
/// firstTerm = emissionPerSecond * timeDelta * assetUnit / totalSupply
/// newIndex = firstTerm + oldIndex
@CharaD7
CharaD7 / PoC_DisputePreemption.t.sol
Last active September 2, 2026 18:50
The Graph Horizon: indexing-dispute ID preemption lets a bad indexer permanently shield faults from slashing. DisputeManager (Arbitrum One proxy 0x2FE023a5 -> impl 0x40b17388), deployed == main 1c9eefde (keccak@441). PoC + write-up + live/pre-upgrade impl source + novelty proofs.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IDisputeManager } from "@graphprotocol/interfaces/contracts/subgraph-service/IDisputeManager.sol";
import { DisputeManagerTest } from "./DisputeManager.t.sol";
/**
* PoC: Indexer permanently shields a fault from ever being disputed.
*
* Indexing dispute ID = keccak256(abi.encodePacked(allocationId, poi, blockNumber)).
@CharaD7
CharaD7 / ens-avatar-selfref-poc.js
Created August 18, 2026 19:33
ENS ens-metadata-service: avatar/header fetch self-referential request amplification (DoS) - PoC harness
// PoC: ens-metadata-service avatar/header image fetch can be turned into a
// self-referential request-amplification loop (DoS on metadata.ens.domains).
//
// Chain (all verified against the repo + the exact npm deps it pins):
// 1. Attacker owns a name and sets its avatar text record to
// https://attacker.example/redir, where /redir 302-redirects to
// https://metadata.ens.domains/mainnet/avatar/<attacker-name>.
// 2. A victim (anyone, including another app that renders avatars) requests
// https://metadata.ens.domains/mainnet/avatar/<attacker-name>.
// 3. src/service/avatar.ts:107-115 calls abortableFetch(avatarURI). That is
@CharaD7
CharaD7 / README.md
Created September 8, 2026 14:07
ENS ens-metadata-service avatar/header image fetch is a self-referential redirect loop that survives fix PR #197 (DoS/amplification on metadata.ens.domains)

ENS ens-metadata-service avatar/header self-referential redirect loop (DoS on metadata.ens.domains)

Full write-up: REPORT_AVATAR_SELFREF.md

Files

  • REPORT_AVATAR_SELFREF.md - full bug report (root cause, attack chain, impact, novelty, references)
  • ens-avatar-selfref-poc.js - PoC 1: reproduces the loop on current master (51x amplification)
  • ens-avatar-selfref-poc-survives197.js - PoC 2: novelty proof that the loop SURVIVES the open fix PR #197
  • package.json - pinned deps (node-fetch@2.7.0, ssrf-req-filter@1.1.1, timeout-signal@2.0.0)
@CharaD7
CharaD7 / termmax_burnToAToken_StealsUnclaimedYield.t.sol
Created September 8, 2026 20:03
TermMax V2 (termstructurelabs) HIGH — theft of unclaimed yield: StableERC4626ForAave.burnToAToken pays raw index-appreciated aTokens against a pinned 1:1 share price (forged PoC + index-aware MockAave)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
//
// TermMax / Term Structure Labs -- High: theft of unclaimed yield
// ===============================================================
// Contract : contracts/v2/tokens/StableERC4626ForAave.sol (TermMax V2)
// Bug : burnToAToken() burns `amount` shares but pays `amount` AAVE aTokens (raw,
// index-unadjusted), while totalAssets() is pinned to totalSupply() (1:1) and the
// Aave interest is quarantined as owner-milked income.
@CharaD7
CharaD7 / termmax_bad_debt_null_result.sol
Created September 8, 2026 20:03
TermMax V2 — INVESTIGATION (NULL RESULT): bad-debt not written down to totalAssets() does NOT reproduce as protocol insolvency; vault stays solvent. Includes trace + repro tests.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
//
// TermMax / Term Structure Labs -- INVESTIGATION (NULL RESULT). Do NOT submit.
// ========================================================================
// Candidate : Protocol insolvency via bad debt never written down to totalAssets()
// Contract : contracts/v2/vault/TermMaxVaultV2.sol + contracts/v2/vault/OrderManagerV2.sol
// Result : The accounting asymmetry is REAL, but the end-to-end insolvency / depositor
// theft DOES NOT REPRODUCE. The vault remains solvent. => Medium, not CRIT/HIGH.
@CharaD7
CharaD7 / olympus_mc11.md
Created September 9, 2026 23:00
Olympus Monocooler (loan market) - setTreasuryBorrower is permissionless before initialization: any caller takes over the treasury-borrower money path (borrow/repay/writeOffDebt) and mints arbitrary debt -> insolvency. Real-contract Foundry PoC proves non-admin takeover + free mint. Latent: live 0xdb59 already initialized.

MonoCooler - setTreasuryBorrower permissionless before initialization (uninitialized-role take-over; latent critical)

Report

Verified against the deployed source and a fork-Foundry PoC. The MonoCooler constructor never sets treasuryBorrower, and the setter is guarded only by if (treasuryBorrower != address(0) && !_isAdmin(msg.sender)) revert. Because a fresh deploy has treasuryBorrower == address(0), the guard short-circuits, so the FIRST caller can point the Cooler at an arbitrary ICoolerTreasuryBorrower and gain control of borrow() / repay() / writeOffDebt().

Severity note: the CURRENTLY-DEPLOYED MonoCooler (0xdb59...e7cc) is already initialized, so this is NOT exploitable on the

@CharaD7
CharaD7 / RailDoSTest.t.sol
Created September 16, 2026 21:05
weETH OFT pairwise rate-limit rail-saturation DoS (live mainnet fork PoC, ether.fi/Immunefi)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { Test } from "forge-std/Test.sol";
import { WeEthAbi } from "../src/WeEthAbi.sol";
/// @notice Live mainnet-fork proof of the per-rail rate-limit DoS on the
/// deployed L1 weETH OFT adapter (EtherFiOFTAdapterUpgradeable).
/// Rail L1->BNB (eid 30102): limit 20 weETH / 14400s, observed live.
contract RailDoSTest is Test {
@CharaD7
CharaD7 / lido_low_poc.sol
Created September 19, 2026 11:10
Lido CSM -- Low Severity PoC: FeeOracle.finalizeUpgradeV3 missing access control. 3/3 tests confirm anyone can call finalizeUpgradeV3.
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.33;
// Lido CSM -- Low Severity: FeeOracle.finalizeUpgradeV3 Missing Access Control
// Target: src/FeeOracle.sol (finalizeUpgradeV3)
// Severity: Low | Program: Lido Immunefi | Primacy of Rules | No KYC
// ChainScope: 871 nodes, 2351 edges, 0 extractor failures, 100% confidence
// The vulnerable function in FeeOracle.sol:
//
@CharaD7
CharaD7 / LIDO_BUG_REPORT.md
Created September 19, 2026 11:32
Lido CSM -- CRITICAL: No-Access-Control Oracle Frame Configuration Manipulation. executeOffsetPhase/executeRestorePhase have no access control. Impact categories: Permanent freezing of funds, Protocol insolvency, Any governance voting result manipulation, Missing access controls, Susceptibility to frontrunning, Theft of tokenized staking yield. …

Lido CSM -- No-Access-Control Oracle Frame Configuration Manipulation

Brief/Intro

TwoPhaseFrameConfigUpdate in lidofinance/community-staking-module has two external functions, executeOffsetPhase() and executeRestorePhase(), with zero access control. Anyone can call them to manipulate the Lido Oracle's frame configuration or permanently renounce MANAGE_FRAME_CONFIG_ROLE on HashConsensus. If exploited in production, an attacker could halt the oracle, disrupt governance voting, and permanently freeze the protocol's ability to adjust oracle parameters.

Vulnerability Details

TwoPhaseFrameConfigUpdate is a helper contract that adjusts the Lido Oracle's frame configuration (epochs per frame, fast lane length) via a two-phase process: