019bb004-7ab1-705e-a818-96d48a80f311
Open this run to answer one question: is this real attacker-relevant behavior with real impact, or just normal contract plumbing?
| ID | Type | Status | Attempts | Heartbeat |
|---|---|---|---|---|
| 39283 | artifact.fetch | complete | 1 / 3 | 3 months ago |
| 39284 | proxy.resolve | complete | 1 / 3 | 3 months ago |
| 39285 | tool.cast_disasm | complete | 1 / 3 | 3 months ago |
| 39286 | analysis.bundle | complete | 1 / 3 | 3 months ago |
| 39287 | capability.graph | complete | 1 / 3 | 3 months ago |
| 39288 | detector.run | complete | 1 / 3 | 3 months ago |
| 39289 | validation.fork | complete | 1 / 3 | 3 months ago |
| 39448 | report.consolidate | complete | 1 / 6 | 3 months ago |
| 39449 | tool.slither | complete | 1 / 2 | 3 months ago |
{
"method": "etherscan+onchain",
"status": "confirmed",
"etherscan_hint": {
"source": "etherscan",
"etherscan": {
"proxy_flag": true,
"implementation": "0x0e41862deeca185f784b96a0bc44de21f0436306"
}
},
"implementation": "0x0e41862deeca185f784b96a0bc44de21f0436306",
"onchain_method": "eip1967"
}
'forge clean' running (wd: /tmp/slither-ojh0l_09) 'forge config --json' running 'forge build --build-info --skip ./test/** ./script/** --force' running (wd: /tmp/slither-ojh0l_09) CrowdfundWithEditionsProxy.constructor(address,address,string,string).logic (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#51) shadows: - CrowdfundWithEditionsProxy.logic() (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#75-79) (function) Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#local-variable-shadowing CrowdfundWithEditionsProxy.constructor(address,address,string,string).operator_ (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#47) lacks a zero-check on : - operator = operator_ (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#68) CrowdfundWithEditionsProxy.constructor(address,address,string,string).treasuryConfig_ (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#46) lacks a zero-check on : - treasuryConfig = treasuryConfig_ (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#69) Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#missing-zero-address-validation CrowdfundWithEditionsProxy.constructor(address,address,string,string) (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#45-72) uses assembly - INLINE ASM (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#53-55) CrowdfundWithEditionsProxy.logic() (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#75-79) uses assembly - INLINE ASM (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#76-78) CrowdfundWithEditionsProxy.fallback() (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#81-104) uses assembly - INLINE ASM (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#82-103) Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage Version constraint 0.8.6 contains known severe issues (https://solidity.readthedocs.io/en/latest/bugs.html) - VerbatimInvalidDeduplication - FullInlinerNonExpressionSplitArgumentEvaluationOrder - MissingSideEffectsOnSelectorAccess - AbiReencodingHeadOverflowWithStaticArrayCleanup - DirtyBytesArrayToStorage - DataLocationChangeInInternalOverride - NestedCalldataArrayAbiReencodingSizeValidation - SignedImmutables. It is used by: - 0.8.6 (contracts/external/ERC20Storage.sol#2) - 0.8.6 (contracts/external/interface/IERC20.sol#2) - 0.8.6 (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#2) - 0.8.6 (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#2) Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-versions-of-solidity Variable CrowdfundWithEditionsStorage.reentrancy_status (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#30) is not in mixedCase Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#conformance-to-solidity-naming-conventions CrowdfundWithEditionsStorage.TOKEN_SCALE (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#21) is never used in CrowdfundWithEditionsProxy (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#30-107) CrowdfundWithEditionsStorage.REENTRANCY_NOT_ENTERED (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#26) is never used in CrowdfundWithEditionsProxy (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#30-107) CrowdfundWithEditionsStorage.REENTRANCY_ENTERED (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#27) is never used in CrowdfundWithEditionsProxy (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#30-107) CrowdfundWithEditionsStorage.reentrancy_status (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#30) is never used in CrowdfundWithEditionsProxy (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol#30-107) Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#unused-state-variable CrowdfundWithEditionsStorage.reentrancy_status (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#30) should be constant Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant CrowdfundWithEditionsStorage.editions (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#58) should be immutable CrowdfundWithEditionsStorage.feePercentage (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#45) should be immutable CrowdfundWithEditionsStorage.fundingCap (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#42) should be immutable CrowdfundWithEditionsStorage.fundingRecipient (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#36) should be immutable CrowdfundWithEditionsStorage.operator (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#33) should be immutable CrowdfundWithEditionsStorage.operatorPercent (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#48) should be immutable CrowdfundWithEditionsStorage.treasuryConfig (contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol#39) should be immutable ERC20Storage.totalSupply (contracts/external/ERC20Storage.sol#16) should be immutable Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-immutable . analyzed (6 contracts with 100 detectors), 21 result(s) found
{
"solc": {
"status": "ok",
"use_rc": 0,
"version": "0.8.6",
"strategy": "solc-select",
"solc_path": "/var/www/tripwire/.venv/bin/solc",
"install_rc": 0,
"use_stderr": null,
"use_stdout": "Switched global version to 0.8.6",
"install_stderr": null,
"install_stdout": "Version '0.8.6' is already installed, skipping..."
},
"solc_args": "--base-path /tmp/slither-ojh0l_09 --allow-paths /tmp/slither-ojh0l_09,/tmp/slither-ojh0l_09/lib,/tmp/slither-ojh0l_09/src",
"remappings": [],
"source_files": [
"contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsProxy.sol",
"contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsStorage.sol",
"contracts/external/ERC20Storage.sol",
"contracts/external/interface/IERC20.sol"
],
"contract_count": 0,
"contract_names": [],
"detector_count": 21,
"workspace_hash": "2dd1dbd6dc7eea5b54f45718e5c4804e028f1ab3acdbbfc14123a839a4eed9be",
"duration_seconds": 0.5152864456176758,
"solc_version_requested": "0.8.6"
}
{"no_findings":false,"summary":"Found two issues in the implementation: an unprotected withdraw path that lets anyone drain funds during funding, and a proxy-unsafe initializer that reverts when called via delegatecall.","findings":[{"severity":"medium","category":"access_control","title":"Unrestricted withdraw allows premature drain during FUNDING","exploit_scenario":"Any address can call withdraw() at any time, including while status is FUNDING. This immediately transfers the entire contract balance to the treasury and fundingRecipient, leaving contributors with minted tokens but no backing ETH and bypassing the closeFunding flow (operator token minting and status progression). A griefer can force early payout and effectively break redemption guarantees.","recommendation":"Restrict withdraw to onlyOperator and/or require status == TRADING, and consider calling it only from closeFunding. Adding nonReentrant to withdraw is also prudent if external recipients are untrusted.","evidence":"withdraw() is public and unguarded, and _withdraw() transfers full balance externally without checking status.","locations":["contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsLogic.sol:151","contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsLogic.sol:254"]},{"severity":"medium","category":"upgradeability","title":"ERC20.initialize reverts when called via proxy, preventing proxy initialization","exploit_scenario":"When used behind a proxy, calling initialize() via delegatecall will make extcodesize(address()) non-zero (the proxy already has code), so initialize reverts. This prevents setting totalSupply/balances through the proxy, leaving the system uninitialized or bricked (e.g., totalSupply remains 0 and critical state may never be set).","recommendation":"Replace the extcodesize construction check with a proper initializer guard (e.g., OpenZeppelin Initializable) that is proxy-safe, or move initialization into the proxy deployment constructor/initializer logic.","evidence":"initialize() uses extcodesize(address()) to allow only constructor-time calls, which fails for proxy delegatecalls.","locations":["contracts/external/ERC20.sol:38"]}]}
OpenAI Codex v0.77.0 (research preview)
--------
workdir: /tmp/codex-d9owvwck
model: gpt-5.2-codex
provider: openai
approval: never
sandbox: read-only
reasoning effort: high
reasoning summaries: auto
session id: 019bb00e-a4b7-7960-9508-41b7b497ec53
--------
user
Context: The user requested the proxy at 0x1b7d237406f51978d48bfcec2211c5eb97a344aa.
Audit the implementation at 0x0e41862deeca185f784b96a0bc44de21f0436306.
Findings should refer to the implementation unless explicitly about proxy mechanics.
You are a security auditor. Audit this Solidity codebase for exploitable vulnerabilities.
Focus on: reentrancy, access control, upgradeability/proxy issues, signature validation, oracle manipulation,
accounting/invariant breaks, external call patterns, unchecked return values, and dangerous delegatecall.
Scope rules:
- You MUST fully read `AUDIT_BUNDLE.txt` before concluding. It contains the complete contents of all first-party Solidity sources in this workspace.
- Treat `lib/` and `@openzeppelin/` as third-party dependencies; skip them unless there is a concrete misuse angle in first-party code.
- If there are only dependency files and no first-party sources, set no_findings=true and explain in summary.
Output MUST be valid JSON matching the provided schema.
- If you find nothing meaningful: set no_findings=true and findings=[].
- Otherwise: set no_findings=false and include findings with severity/category/title and file/line locations when possible.
Output constraints (IMPORTANT):
- severity MUST be exactly one of: info, low, medium, high, critical (lowercase).
- category MUST be exactly one of: access_control, reentrancy, math, oracle, upgradeability, auth, other.
Keep summary short and concrete.
mcp startup: no servers
thinking
**Preparing to audit bundle read-only**
exec
/bin/bash -lc ls in /tmp/codex-d9owvwck succeeded in 8ms:
AUDIT_BUNDLE.txt
codex-output-schema.json
contracts
exec
/bin/bash -lc 'cat AUDIT_BUNDLE.txt' in /tmp/codex-d9owvwck succeeded in 5ms:
This file concatenates the full contents of first-party Solidity sources for auditing.
Do not treat dependency code under lib/ or @openzeppelin/ as first-party.
================================================================================
FILE: contracts/external/ERC20.sol
================================================================================
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.6;
// import {ERC20Storage} from "./ERC20Storage.sol";
import {IERC20, IERC20Events} from "./interface/IERC20.sol";
/**
* @title ERC20 Implementation.
* @author MirrorXYZ
*/
contract ERC20 is IERC20, IERC20Events {
// ============ ERC20 Attributes ============
/// @notice EIP-20 token name for this token
string public override name;
thinking
**Auditing fund withdrawal and reentrancy risks**
I'm carefully reviewing the contract's withdraw function, which is publicly callable without access control and can prematurely release funds during the FUNDING phase—potentially griefing contributors by draining escrowed ETH early. I'm also analyzing reentrancy concerns since withdraw lacks a reentrancy guard and makes external calls, which could allow nested calls and unintended transfers. Additionally, I'm considering initialization and upgradeability issues with the proxy pattern and how token redemption logic aligns with the funding and withdrawal flow. Next, I'll locate relevant file lines to support clear issue reporting.
exec
/bin/bash -lc 'nl -ba contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsLogic.sol' in /tmp/codex-d9owvwck succeeded in 24ms:
1 // SPDX-License-Identifier: GPL-3.0-or-later
2 pragma solidity 0.8.6;
3
4 import {CrowdfundWithEditionsStorage} from "./CrowdfundWithEditionsStorage.sol";
5 import {ERC20} from "../../../external/ERC20.sol";
6 import {ICrowdfundWithEditions} from "./interface/ICrowdfundWithEditions.sol";
7 import {ITreasuryConfig} from "../../../interface/ITreasuryConfig.sol";
8
9 /**
10 * @title CrowdfundWithEditionsLogic
11 * @author MirrorXYZ
12 *
13 * Crowdfund the creation of NFTs by issuing ERC20 tokens that
14 * can be redeemed for the underlying value of the NFT once sold.
15 */
16 contract CrowdfundWithEditionsLogic is CrowdfundWithEditionsStorage, ERC20 {
17 // ============ Events ============
18
19 event ReceivedERC721(uint256 tokenId, address sender);
20 event Contribution(address contributor, uint256 amount);
thinking
**Adding initialization lines to ERC20**
exec
/bin/bash -lc 'nl -ba contracts/external/ERC20.sol' in /tmp/codex-d9owvwck succeeded in 5ms:
1 // SPDX-License-Identifier: GPL-3.0-or-later
2 pragma solidity 0.8.6;
3
4 // import {ERC20Storage} from "./ERC20Storage.sol";
5 import {IERC20, IERC20Events} from "./interface/IERC20.sol";
6
7 /**
8 * @title ERC20 Implementation.
9 * @author MirrorXYZ
10 */
11 contract ERC20 is IERC20, IERC20Events {
12 // ============ ERC20 Attributes ============
13 /// @notice EIP-20 token name for this token
14 string public override name;
15
16 /// @notice EIP-20 token symbol for this token
17 string public override symbol;
18
19 /// @notice EIP-20 token decimals for this token
20 uint8 public constant override decimals = 18;
thinking
**Analyzing reentrancy and initialization vulnerabilities**
I'm mapping out subtle reentrancy risks around the withdraw function, especially how its lack of a guard can let a malicious treasury contract repeatedly claim fees, inflating what it receives. I'm also flagging a critical upgradeability trap where the ERC20.initialize guard blocks proxy initialization, potentially leaving the proxy uninitialized and bricked. Both deserve clear findings with severity and remediation suggestions.
codex
{"no_findings":false,"summary":"Found two issues in the implementation: an unprotected withdraw path that lets anyone drain funds during funding, and a proxy-unsafe initializer that reverts when called via delegatecall.","findings":[{"severity":"medium","category":"access_control","title":"Unrestricted withdraw allows premature drain during FUNDING","exploit_scenario":"Any address can call withdraw() at any time, including while status is FUNDING. This immediately transfers the entire contract balance to the treasury and fundingRecipient, leaving contributors with minted tokens but no backing ETH and bypassing the closeFunding flow (operator token minting and status progression). A griefer can force early payout and effectively break redemption guarantees.","recommendation":"Restrict withdraw to onlyOperator and/or require status == TRADING, and consider calling it only from closeFunding. Adding nonReentrant to withdraw is also prudent if external recipients are untrusted.","evidence":"withdraw() is public and unguarded, and _withdraw() transfers full balance externally without checking status.","locations":["contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsLogic.sol:151","contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsLogic.sol:254"]},{"severity":"medium","category":"upgradeability","title":"ERC20.initialize reverts when called via proxy, preventing proxy initialization","exploit_scenario":"When used behind a proxy, calling initialize() via delegatecall will make extcodesize(address()) non-zero (the proxy already has code), so initialize reverts. This prevents setting totalSupply/balances through the proxy, leaving the system uninitialized or bricked (e.g., totalSupply remains 0 and critical state may never be set).","recommendation":"Replace the extcodesize construction check with a proper initializer guard (e.g., OpenZeppelin Initializable) that is proxy-safe, or move initialization into the proxy deployment constructor/initializer logic.","evidence":"initialize() uses extcodesize(address()) to allow only constructor-time calls, which fails for proxy delegatecalls.","locations":["contracts/external/ERC20.sol:38"]}]}
tokens used
20,081
{
"codex": {
"ran_at": "2026-01-12T02:37:27.034800+00:00",
"returncode": 0
},
"project": {
"mode": "source",
"file_count": 6,
"import_count": 6,
"first_party_contracts_count": 6
},
"summary": "Found two issues in the implementation: an unprotected withdraw path that lets anyone drain funds during funding, and a proxy-unsafe initializer that reverts when called via delegatecall.",
"raw_final": {
"summary": "Found two issues in the implementation: an unprotected withdraw path that lets anyone drain funds during funding, and a proxy-unsafe initializer that reverts when called via delegatecall.",
"findings": [
{
"title": "Unrestricted withdraw allows premature drain during FUNDING",
"category": "access_control",
"evidence": "withdraw() is public and unguarded, and _withdraw() transfers full balance externally without checking status.",
"severity": "medium",
"locations": [
"contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsLogic.sol:151",
"contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsLogic.sol:254"
],
"recommendation": "Restrict withdraw to onlyOperator and/or require status == TRADING, and consider calling it only from closeFunding. Adding nonReentrant to withdraw is also prudent if external recipients are untrusted.",
"exploit_scenario": "Any address can call withdraw() at any time, including while status is FUNDING. This immediately transfers the entire contract balance to the treasury and fundingRecipient, leaving contributors with minted tokens but no backing ETH and bypassing the closeFunding flow (operator token minting and status progression). A griefer can force early payout and effectively break redemption guarantees."
},
{
"title": "ERC20.initialize reverts when called via proxy, preventing proxy initialization",
"category": "upgradeability",
"evidence": "initialize() uses extcodesize(address()) to allow only constructor-time calls, which fails for proxy delegatecalls.",
"severity": "medium",
"locations": [
"contracts/external/ERC20.sol:38"
],
"recommendation": "Replace the extcodesize construction check with a proper initializer guard (e.g., OpenZeppelin Initializable) that is proxy-safe, or move initialization into the proxy deployment constructor/initializer logic.",
"exploit_scenario": "When used behind a proxy, calling initialize() via delegatecall will make extcodesize(address()) non-zero (the proxy already has code), so initialize reverts. This prevents setting totalSupply/balances through the proxy, leaving the system uninitialized or bricked (e.g., totalSupply remains 0 and critical state may never be set)."
}
],
"no_findings": false
},
"no_findings": false,
"proxy_context": {
"proxy_run_id": "019bb004-7ab1-705e-a818-96d48a80f311",
"proxy_address": "0x1b7d237406f51978d48bfcec2211c5eb97a344aa",
"implementation_run_id": "019bb004-9839-71fb-bf53-cdb271c42b17",
"implementation_address": "0x0e41862deeca185f784b96a0bc44de21f0436306"
},
"schema_version": 1
}
00000000: PUSH1 0x80 00000002: PUSH1 0x40 00000004: MSTORE 00000005: PUSH1 0x04 00000007: CALLDATASIZE 00000008: LT 00000009: PUSH2 0x00cb 0000000c: JUMPI 0000000d: PUSH1 0x00 0000000f: CALLDATALOAD 00000010: PUSH1 0xe0 00000012: SHR 00000013: DUP1 00000014: PUSH4 0x95d89b41 00000019: GT 0000001a: PUSH2 0x0074 0000001d: JUMPI 0000001e: DUP1 0000001f: PUSH4 0xcfd7b0df 00000024: GT 00000025: PUSH2 0x004e 00000028: JUMPI 00000029: DUP1 0000002a: PUSH4 0xcfd7b0df 0000002f: EQ 00000030: PUSH2 0x0280 00000033: JUMPI 00000034: DUP1 00000035: PUSH4 0xd7dfa0dd 0000003a: EQ 0000003b: PUSH2 0x02ad 0000003e: JUMPI 0000003f: DUP1 00000040: PUSH4 0xe3b2594f 00000045: EQ 00000046: PUSH2 0x02e1 00000049: JUMPI 0000004a: PUSH2 0x00d2 0000004d: JUMP 0000004e: JUMPDEST 0000004f: DUP1 00000050: PUSH4 0x95d89b41 00000055: EQ 00000056: PUSH2 0x0223 00000059: JUMPI 0000005a: DUP1 0000005b: PUSH4 0xa001ecdd 00000060: EQ 00000061: PUSH2 0x0238 00000064: JUMPI 00000065: DUP1 00000066: PUSH4 0xb8ddbcb3 0000006b: EQ 0000006c: PUSH2 0x024e 0000006f: JUMPI 00000070: PUSH2 0x00d2 00000073: JUMP 00000074: JUMPDEST 00000075: DUP1 00000076: PUSH4 0x200d2ed2 0000007b: GT 0000007c: PUSH2 0x00a5 0000007f: JUMPI 00000080: DUP1 00000081: PUSH4 0x200d2ed2 00000086: EQ 00000087: PUSH2 0x01b9 0000008a: JUMPI 0000008b: DUP1 0000008c: PUSH4 0x570ca735 00000091: EQ 00000092: PUSH2 0x01e0 00000095: JUMPI 00000096: DUP1 00000097: PUSH4 0x7b4044a0 0000009c: EQ 0000009d: PUSH2 0x020d 000000a0: JUMPI 000000a1: PUSH2 0x00d2 000000a4: JUMP 000000a5: JUMPDEST 000000a6: DUP1 000000a7: PUSH4 0x06fdde03 000000ac: EQ 000000ad: PUSH2 0x0118 000000b0: JUMPI 000000b1: DUP1 000000b2: PUSH4 0x18160ddd 000000b7: EQ 000000b8: PUSH2 0x0143 000000bb: JUMPI 000000bc: DUP1 000000bd: PUSH4 0x1bb534ba 000000c2: EQ 000000c3: PUSH2 0x0167 000000c6: JUMPI 000000c7: PUSH2 0x00d2 000000ca: JUMP 000000cb: JUMPDEST 000000cc: CALLDATASIZE 000000cd: PUSH2 0x00d2 000000d0: JUMPI 000000d1: STOP 000000d2: JUMPDEST 000000d3: PUSH1 0x40 000000d5: MLOAD 000000d6: CALLDATASIZE 000000d7: PUSH1 0x00 000000d9: DUP3 000000da: CALLDATACOPY 000000db: PUSH1 0x00 000000dd: DUP1 000000de: CALLDATASIZE 000000df: DUP4 000000e0: PUSH32 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc 00000101: SLOAD 00000102: GAS 00000103: DELEGATECALL 00000104: RETURNDATASIZE 00000105: DUP1 00000106: PUSH1 0x00 00000108: DUP5 00000109: RETURNDATACOPY 0000010a: DUP2 0000010b: DUP1 0000010c: ISZERO 0000010d: PUSH2 0x0114 00000110: JUMPI 00000111: DUP2 00000112: DUP5 00000113: RETURN 00000114: JUMPDEST 00000115: DUP2 00000116: DUP5 00000117: REVERT 00000118: JUMPDEST 00000119: CALLVALUE 0000011a: DUP1 0000011b: ISZERO 0000011c: PUSH2 0x0124 0000011f: JUMPI 00000120: PUSH1 0x00 00000122: DUP1 00000123: REVERT 00000124: JUMPDEST 00000125: POP 00000126: PUSH2 0x012d 00000129: PUSH2 0x02f7 0000012c: JUMP 0000012d: JUMPDEST 0000012e: PUSH1 0x40 00000130: MLOAD 00000131: PUSH2 0x013a 00000134: SWAP2 00000135: SWAP1 00000136: PUSH2 0x03d3 00000139: JUMP 0000013a: JUMPDEST 0000013b: PUSH1 0x40 0000013d: MLOAD 0000013e: DUP1 0000013f: SWAP2 00000140: SUB 00000141: SWAP1 00000142: RETURN 00000143: JUMPDEST 00000144: CALLVALUE 00000145: DUP1 00000146: ISZERO 00000147: PUSH2 0x014f 0000014a: JUMPI 0000014b: PUSH1 0x00 0000014d: DUP1 0000014e: REVERT 0000014f: JUMPDEST 00000150: POP 00000151: PUSH2 0x0159 00000154: PUSH1 0x0a 00000156: SLOAD 00000157: DUP2 00000158: JUMP 00000159: JUMPDEST 0000015a: PUSH1 0x40 0000015c: MLOAD 0000015d: SWAP1 0000015e: DUP2 0000015f: MSTORE 00000160: PUSH1 0x20 00000162: ADD 00000163: PUSH2 0x013a 00000166: JUMP 00000167: JUMPDEST 00000168: CALLVALUE 00000169: DUP1 0000016a: ISZERO 0000016b: PUSH2 0x0173 0000016e: JUMPI 0000016f: PUSH1 0x00 00000171: DUP1 00000172: REVERT 00000173: JUMPDEST 00000174: POP 00000175: PUSH1 0x02 00000177: SLOAD 00000178: PUSH2 0x0194 0000017b: SWAP1 0000017c: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000191: AND 00000192: DUP2 00000193: JUMP 00000194: JUMPDEST 00000195: PUSH1 0x40 00000197: MLOAD 00000198: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000001ad: SWAP1 000001ae: SWAP2 000001af: AND 000001b0: DUP2 000001b1: MSTORE 000001b2: PUSH1 0x20 000001b4: ADD 000001b5: PUSH2 0x013a 000001b8: JUMP 000001b9: JUMPDEST 000001ba: CALLVALUE 000001bb: DUP1 000001bc: ISZERO 000001bd: PUSH2 0x01c5 000001c0: JUMPI 000001c1: PUSH1 0x00 000001c3: DUP1 000001c4: REVERT 000001c5: JUMPDEST 000001c6: POP 000001c7: PUSH1 0x07 000001c9: SLOAD 000001ca: PUSH2 0x01d3 000001cd: SWAP1 000001ce: PUSH1 0xff 000001d0: AND 000001d1: DUP2 000001d2: JUMP 000001d3: JUMPDEST 000001d4: PUSH1 0x40 000001d6: MLOAD 000001d7: PUSH2 0x013a 000001da: SWAP2 000001db: SWAP1 000001dc: PUSH2 0x0392 000001df: JUMP 000001e0: JUMPDEST 000001e1: CALLVALUE 000001e2: DUP1 000001e3: ISZERO 000001e4: PUSH2 0x01ec 000001e7: JUMPI 000001e8: PUSH1 0x00 000001ea: DUP1 000001eb: REVERT 000001ec: JUMPDEST 000001ed: POP 000001ee: PUSH1 0x01 000001f0: SLOAD 000001f1: PUSH2 0x0194 000001f4: SWAP1 000001f5: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000020a: AND 0000020b: DUP2 0000020c: JUMP 0000020d: JUMPDEST 0000020e: CALLVALUE 0000020f: DUP1 00000210: ISZERO 00000211: PUSH2 0x0219 00000214: JUMPI 00000215: PUSH1 0x00 00000217: DUP1 00000218: REVERT 00000219: JUMPDEST 0000021a: POP 0000021b: PUSH2 0x0159 0000021e: PUSH1 0x06 00000220: SLOAD 00000221: DUP2 00000222: JUMP 00000223: JUMPDEST 00000224: CALLVALUE 00000225: DUP1 00000226: ISZERO 00000227: PUSH2 0x022f 0000022a: JUMPI 0000022b: PUSH1 0x00 0000022d: DUP1 0000022e: REVERT 0000022f: JUMPDEST 00000230: POP 00000231: PUSH2 0x012d 00000234: PUSH2 0x0385 00000237: JUMP 00000238: JUMPDEST 00000239: CALLVALUE 0000023a: DUP1 0000023b: ISZERO 0000023c: PUSH2 0x0244 0000023f: JUMPI 00000240: PUSH1 0x00 00000242: DUP1 00000243: REVERT 00000244: JUMPDEST 00000245: POP 00000246: PUSH2 0x0159 00000249: PUSH1 0x05 0000024b: SLOAD 0000024c: DUP2 0000024d: JUMP 0000024e: JUMPDEST 0000024f: CALLVALUE 00000250: DUP1 00000251: ISZERO 00000252: PUSH2 0x025a 00000255: JUMPI 00000256: PUSH1 0x00 00000258: DUP1 00000259: REVERT 0000025a: JUMPDEST 0000025b: POP 0000025c: PUSH1 0x07 0000025e: SLOAD 0000025f: PUSH2 0x0194 00000262: SWAP1 00000263: PUSH2 0x0100 00000266: SWAP1 00000267: DIV 00000268: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000027d: AND 0000027e: DUP2 0000027f: JUMP 00000280: JUMPDEST 00000281: CALLVALUE 00000282: DUP1 00000283: ISZERO 00000284: PUSH2 0x028c 00000287: JUMPI 00000288: PUSH1 0x00 0000028a: DUP1 0000028b: REVERT 0000028c: JUMPDEST 0000028d: POP 0000028e: PUSH1 0x03 00000290: SLOAD 00000291: PUSH2 0x0194 00000294: SWAP1 00000295: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000002aa: AND 000002ab: DUP2 000002ac: JUMP 000002ad: JUMPDEST 000002ae: CALLVALUE 000002af: DUP1 000002b0: ISZERO 000002b1: PUSH2 0x02b9 000002b4: JUMPI 000002b5: PUSH1 0x00 000002b7: DUP1 000002b8: REVERT 000002b9: JUMPDEST 000002ba: POP 000002bb: PUSH32 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc 000002dc: SLOAD 000002dd: PUSH2 0x0194 000002e0: JUMP 000002e1: JUMPDEST 000002e2: CALLVALUE 000002e3: DUP1 000002e4: ISZERO 000002e5: PUSH2 0x02ed 000002e8: JUMPI 000002e9: PUSH1 0x00 000002eb: DUP1 000002ec: REVERT 000002ed: JUMPDEST 000002ee: POP 000002ef: PUSH2 0x0159 000002f2: PUSH1 0x04 000002f4: SLOAD 000002f5: DUP2 000002f6: JUMP 000002f7: JUMPDEST 000002f8: PUSH1 0x08 000002fa: DUP1 000002fb: SLOAD 000002fc: PUSH2 0x0304 000002ff: SWAP1 00000300: PUSH2 0x0446 00000303: JUMP 00000304: JUMPDEST 00000305: DUP1 00000306: PUSH1 0x1f 00000308: ADD 00000309: PUSH1 0x20 0000030b: DUP1 0000030c: SWAP2 0000030d: DIV 0000030e: MUL 0000030f: PUSH1 0x20 00000311: ADD 00000312: PUSH1 0x40 00000314: MLOAD 00000315: SWAP1 00000316: DUP2 00000317: ADD 00000318: PUSH1 0x40 0000031a: MSTORE 0000031b: DUP1 0000031c: SWAP3 0000031d: SWAP2 0000031e: SWAP1 0000031f: DUP2 00000320: DUP2 00000321: MSTORE 00000322: PUSH1 0x20 00000324: ADD 00000325: DUP3 00000326: DUP1 00000327: SLOAD 00000328: PUSH2 0x0330 0000032b: SWAP1 0000032c: PUSH2 0x0446 0000032f: JUMP 00000330: JUMPDEST 00000331: DUP1 00000332: ISZERO 00000333: PUSH2 0x037d 00000336: JUMPI 00000337: DUP1 00000338: PUSH1 0x1f 0000033a: LT 0000033b: PUSH2 0x0352 0000033e: JUMPI 0000033f: PUSH2 0x0100 00000342: DUP1 00000343: DUP4 00000344: SLOAD 00000345: DIV 00000346: MUL 00000347: DUP4 00000348: MSTORE 00000349: SWAP2 0000034a: PUSH1 0x20 0000034c: ADD 0000034d: SWAP2 0000034e: PUSH2 0x037d 00000351: JUMP 00000352: JUMPDEST 00000353: DUP3 00000354: ADD 00000355: SWAP2 00000356: SWAP1 00000357: PUSH1 0x00 00000359: MSTORE 0000035a: PUSH1 0x20 0000035c: PUSH1 0x00 0000035e: KECCAK256 0000035f: SWAP1 00000360: JUMPDEST 00000361: DUP2 00000362: SLOAD 00000363: DUP2 00000364: MSTORE 00000365: SWAP1 00000366: PUSH1 0x01 00000368: ADD 00000369: SWAP1 0000036a: PUSH1 0x20 0000036c: ADD 0000036d: DUP1 0000036e: DUP4 0000036f: GT 00000370: PUSH2 0x0360 00000373: JUMPI 00000374: DUP3 00000375: SWAP1 00000376: SUB 00000377: PUSH1 0x1f 00000379: AND 0000037a: DUP3 0000037b: ADD 0000037c: SWAP2 0000037d: JUMPDEST 0000037e: POP 0000037f: POP 00000380: POP 00000381: POP 00000382: POP 00000383: DUP2 00000384: JUMP 00000385: JUMPDEST 00000386: PUSH1 0x09 00000388: DUP1 00000389: SLOAD 0000038a: PUSH2 0x0304 0000038d: SWAP1 0000038e: PUSH2 0x0446 00000391: JUMP 00000392: JUMPDEST 00000393: PUSH1 0x20 00000395: DUP2 00000396: ADD 00000397: PUSH1 0x02 00000399: DUP4 0000039a: LT 0000039b: PUSH2 0x03cd 0000039e: JUMPI 0000039f: PUSH32 0x4e487b7100000000000000000000000000000000000000000000000000000000 000003c0: PUSH1 0x00 000003c2: MSTORE 000003c3: PUSH1 0x21 000003c5: PUSH1 0x04 000003c7: MSTORE 000003c8: PUSH1 0x24 000003ca: PUSH1 0x00 000003cc: REVERT 000003cd: JUMPDEST 000003ce: SWAP2 000003cf: SWAP1 000003d0: MSTORE 000003d1: SWAP1 000003d2: JUMP 000003d3: JUMPDEST 000003d4: PUSH1 0x00 000003d6: PUSH1 0x20 000003d8: DUP1 000003d9: DUP4 000003da: MSTORE 000003db: DUP4 000003dc: MLOAD 000003dd: DUP1 000003de: DUP3 000003df: DUP6 000003e0: ADD 000003e1: MSTORE 000003e2: PUSH1 0x00 000003e4: JUMPDEST 000003e5: DUP2 000003e6: DUP2 000003e7: LT 000003e8: ISZERO 000003e9: PUSH2 0x0400 000003ec: JUMPI 000003ed: DUP6 000003ee: DUP2 000003ef: ADD 000003f0: DUP4 000003f1: ADD 000003f2: MLOAD 000003f3: DUP6 000003f4: DUP3 000003f5: ADD 000003f6: PUSH1 0x40 000003f8: ADD 000003f9: MSTORE 000003fa: DUP3 000003fb: ADD 000003fc: PUSH2 0x03e4 000003ff: JUMP 00000400: JUMPDEST 00000401: DUP2 00000402: DUP2 00000403: GT 00000404: ISZERO 00000405: PUSH2 0x0412 00000408: JUMPI 00000409: PUSH1 0x00 0000040b: PUSH1 0x40 0000040d: DUP4 0000040e: DUP8 0000040f: ADD 00000410: ADD 00000411: MSTORE 00000412: JUMPDEST 00000413: POP 00000414: PUSH1 0x1f 00000416: ADD 00000417: PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 00000438: AND 00000439: SWAP3 0000043a: SWAP1 0000043b: SWAP3 0000043c: ADD 0000043d: PUSH1 0x40 0000043f: ADD 00000440: SWAP4 00000441: SWAP3 00000442: POP 00000443: POP 00000444: POP 00000445: JUMP 00000446: JUMPDEST 00000447: PUSH1 0x01 00000449: DUP2 0000044a: DUP2 0000044b: SHR 0000044c: SWAP1 0000044d: DUP3 0000044e: AND 0000044f: DUP1 00000450: PUSH2 0x045a 00000453: JUMPI 00000454: PUSH1 0x7f 00000456: DUP3 00000457: AND 00000458: SWAP2 00000459: POP 0000045a: JUMPDEST 0000045b: PUSH1 0x20 0000045d: DUP3 0000045e: LT 0000045f: DUP2 00000460: EQ 00000461: ISZERO 00000462: PUSH2 0x0494 00000465: JUMPI 00000466: PUSH32 0x4e487b7100000000000000000000000000000000000000000000000000000000 00000487: PUSH1 0x00 00000489: MSTORE 0000048a: PUSH1 0x22 0000048c: PUSH1 0x04 0000048e: MSTORE 0000048f: PUSH1 0x24 00000491: PUSH1 0x00 00000493: REVERT 00000494: JUMPDEST 00000495: POP 00000496: SWAP2 00000497: SWAP1 00000498: POP 00000499: JUMP 0000049a: INVALID 0000049b: LOG2 0000049c: PUSH5 0x6970667358 000004a2: UNKNOWN(0x22) 000004a3: SLT 000004a4: KECCAK256 000004a5: PUSH22 0xe2c11b94fd8bff7467563877afbbd5b54be285e95731 000004bc: SDIV 000004bd: PUSH22
| Severity | Category | Tool | Title | Confidence | Validated | Confirmed | Details |
|---|---|---|---|---|---|---|---|
| critical | upgradeability | detector | Untrusted DELEGATECALL target reachable | 70 | no | no |
viewtrace_id: 0xcc1d8f4300ffa6091ecfb4f1030b7bf6df2f8217ebb56f212503ec8444bec76a
validation_json{
"sink": "DELEGATECALL",
"errors": 0,
"status": "unknown",
"attempts": 144,
"trace_id": "0xcc1d8f4300ffa6091ecfb4f1030b7bf6df2f8217ebb56f212503ec8444bec76a",
"confirmed": false,
"trace_mode": "callTracer",
"call_targets": null,
"matched_probe": null,
"target_varies": null,
"classification": "no_sink"
}
witness_json{
"notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
"constraints": [],
"entrypoints": [
{
"calldata": "0xcfd7b0df",
"selector": "0xcfd7b0df",
"calldata_variants": [
"0xcfd7b0df",
"0xcfd7b0df0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xd7dfa0dd",
"selector": "0xd7dfa0dd",
"calldata_variants": [
"0xd7dfa0dd",
"0xd7dfa0dd0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xe3b2594f",
"selector": "0xe3b2594f",
"calldata_variants": [
"0xe3b2594f",
"0xe3b2594f0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x95d89b41",
"selector": "0x95d89b41",
"calldata_variants": [
"0x95d89b41",
"0x95d89b410000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xa001ecdd",
"selector": "0xa001ecdd",
"calldata_variants": [
"0xa001ecdd",
"0xa001ecdd0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xb8ddbcb3",
"selector": "0xb8ddbcb3",
"calldata_variants": [
"0xb8ddbcb3",
"0xb8ddbcb30000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x200d2ed2",
"selector": "0x200d2ed2",
"calldata_variants": [
"0x200d2ed2",
"0x200d2ed20000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x570ca735",
"selector": "0x570ca735",
"calldata_variants": [
"0x570ca735",
"0x570ca7350000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"examples": [
{
"pc": 259,
"opcode": "DELEGATECALL",
"returndata_checked": null,
"value_expression_category": "n/a",
"target_expression_category": "computed"
}
],
"guards_detected": [],
"delegatecall_count": 1,
"untrusted_delegatecall_count": 1
}
|
| medium | access_control | codex | Unrestricted withdraw allows premature drain during FUNDING | 75 | no | — |
viewevidence_json{
"evidence": "withdraw() is public and unguarded, and _withdraw() transfers full balance externally without checking status.",
"locations": [
"contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsLogic.sol:151",
"contracts/producers/crowdfunds/crowdfund-with-editions/CrowdfundWithEditionsLogic.sol:254"
],
"recommendation": "Restrict withdraw to onlyOperator and/or require status == TRADING, and consider calling it only from closeFunding. Adding nonReentrant to withdraw is also prudent if external recipients are untrusted.",
"exploit_scenario": "Any address can call withdraw() at any time, including while status is FUNDING. This immediately transfers the entire contract balance to the treasury and fundingRecipient, leaving contributors with minted tokens but no backing ETH and bypassing the closeFunding flow (operator token minting and status progression). A griefer can force early payout and effectively break redemption guarantees."
}
|
| medium | upgradeability | codex | ERC20.initialize reverts when called via proxy, preventing proxy initialization | 75 | no | — |
viewevidence_json{
"evidence": "initialize() uses extcodesize(address()) to allow only constructor-time calls, which fails for proxy delegatecalls.",
"locations": [
"contracts/external/ERC20.sol:38"
],
"recommendation": "Replace the extcodesize construction check with a proper initializer guard (e.g., OpenZeppelin Initializable) that is proxy-safe, or move initialization into the proxy deployment constructor/initializer logic.",
"exploit_scenario": "When used behind a proxy, calling initialize() via delegatecall will make extcodesize(address()) non-zero (the proxy already has code), so initialize reverts. This prevents setting totalSupply/balances through the proxy, leaving the system uninitialized or bricked (e.g., totalSupply remains 0 and critical state may never be set)."
}
|
| medium | upgradeability | cast | DELEGATECALL present | 80 | no | — |
viewevidence_json{
"notes": "delegatecall enables execution in caller context; common in proxies/upgradeable patterns",
"delegatecall_count": 1
}
|