{"bundle_version":1,"target":{"id":"omniguard-production-20261114","name":"OmniGuard production acceptance fixture","kind":"isolated-fixture"},"revision":"production-vulnerable-v0.1.4","rules":["OG-SOL-001","OG-SOL-002","OG-SOL-003","OG-SOL-004","OG-SOL-005","OG-SOL-006","OG-SOL-007","OG-SOL-008","OG-SOL-009","OG-SOL-010","OG-SOL-011","OG-SOL-012"],"report":{"schema_version":3,"engine_version":"0.1.4","scanned_files":1,"analysis":{"mode":"solc","compiler_version":"0.8.26+commit.8a97fa7a.Linux.g++"},"coverage":{"rule_set":"solidity-core/2026.11","rules":["OG-SOL-001","OG-SOL-002","OG-SOL-003","OG-SOL-004","OG-SOL-005","OG-SOL-006","OG-SOL-007","OG-SOL-008","OG-SOL-009","OG-SOL-010","OG-SOL-011","OG-SOL-012"],"files":["EffectVault.sol"],"source_sha256":{"EffectVault.sol":"ea933c4380fd876fd25bff485be6980573cd25a8c67ff84841927fbc48ee18f8"},"complete":true},"diagnostics":[],"findings":[{"id":"f4c0fa6bad9f5ff6fb11dd9a","rule_id":"OG-SOL-002","title":"State write follows an external call","severity":"high","confidence":"medium","message":"An external interaction precedes a write to this contract's storage on a modeled execution path.","remediation":"Apply checks-effects-interactions and verify a reentrancy guard with a local regression test.","location":{"file":"EffectVault.sol","start_line":20,"start_column":9,"end_line":20,"end_column":43,"byte_start":557,"byte_end":591},"evidence":{"source_sha256":"ea933c4380fd876fd25bff485be6980573cd25a8c67ff84841927fbc48ee18f8","excerpt":"_send(payable(msg.sender), amount)","validated":true,"related":[{"source_sha256":"ea933c4380fd876fd25bff485be6980573cd25a8c67ff84841927fbc48ee18f8","label":"Resolved external interaction","location":{"file":"EffectVault.sol","start_line":25,"start_column":22,"end_line":25,"end_column":55,"byte_start":720,"byte_end":753},"excerpt":"recipient.call{value: amount}(\"\")"},{"source_sha256":"ea933c4380fd876fd25bff485be6980573cd25a8c67ff84841927fbc48ee18f8","label":"Later storage write","location":{"file":"EffectVault.sol","start_line":21,"start_column":9,"end_line":21,"end_column":26,"byte_start":601,"byte_end":618},"excerpt":"credit.amount = 0"},{"source_sha256":"ea933c4380fd876fd25bff485be6980573cd25a8c67ff84841927fbc48ee18f8","label":"Compiler-resolved storage root","location":{"file":"EffectVault.sol","start_line":6,"start_column":5,"end_line":6,"end_column":47,"byte_start":122,"byte_end":164},"excerpt":"mapping(address => Credit) private credits"},{"source_sha256":"ea933c4380fd876fd25bff485be6980573cd25a8c67ff84841927fbc48ee18f8","label":"Resolved effect binding or call chain","location":{"file":"EffectVault.sol","start_line":20,"start_column":9,"end_line":20,"end_column":43,"byte_start":557,"byte_end":591},"excerpt":"_send(payable(msg.sender), amount)"},{"source_sha256":"ea933c4380fd876fd25bff485be6980573cd25a8c67ff84841927fbc48ee18f8","label":"Resolved effect binding or call chain","location":{"file":"EffectVault.sol","start_line":24,"start_column":5,"end_line":27,"end_column":6,"byte_start":631,"byte_end":796},"excerpt":"function _send(address payable recipient, uint256 amount) private {\n        (bool ok,) = recipient.call{value: amount}(\"\");\n        require(ok, \"send failed\");\n    }"},{"source_sha256":"ea933c4380fd876fd25bff485be6980573cd25a8c67ff84841927fbc48ee18f8","label":"Resolved effect binding or call chain","location":{"file":"EffectVault.sol","start_line":17,"start_column":9,"end_line":17,"end_column":52,"byte_start":421,"byte_end":464},"excerpt":"Credit storage credit = credits[msg.sender]"}]},"context":{"contract":"EffectVault","function":"withdraw"}}]},"sources":[{"path":"EffectVault.sol","sha256":"ea933c4380fd876fd25bff485be6980573cd25a8c67ff84841927fbc48ee18f8","content":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\ncontract EffectVault {\n    struct Credit { uint256 amount; }\n    mapping(address => Credit) private credits;\n\n    function deposit() external payable {\n        credits[msg.sender].amount += msg.value;\n    }\n\n    function balanceOf(address who) external view returns (uint256) {\n        return credits[who].amount;\n    }\n\n    function withdraw() external {\n        Credit storage credit = credits[msg.sender];\n        uint256 amount = credit.amount;\n        require(amount != 0, \"no credit\");\n        _send(payable(msg.sender), amount);\n        credit.amount = 0;\n    }\n\n    function _send(address payable recipient, uint256 amount) private {\n        (bool ok,) = recipient.call{value: amount}(\"\");\n        require(ok, \"send failed\");\n    }\n}\n"}]}
