Skip to content
Opsec

Smart contracts & crypto protocols

The contract agent reasons about value flow, external calls and protocol invariants, then proves each issue on a fork of the chain your protocol actually runs on.

Coverage

  • Solidity
  • Vyper
  • Rust
  • Move

What it finds

Vulnerability classes, confirmed.

  • Confirmed class

    Reentrancy

    Single-function, cross-function and read-only reentrancy across contracts and protocols.

  • Confirmed class

    Oracle manipulation

    Stale rounds, spot-price reads and flash-loan driven price movement.

  • Confirmed class

    Access control

    Unprotected initializers, missing role checks and upgrade paths that bypass governance.

  • Confirmed class

    Invariant violations

    Accounting drift, share inflation and rounding that can be compounded into loss.

  • Confirmed class

    Signature handling

    Replay across chains, malleability and permit flows missing nonces or deadlines.

  • Confirmed class

    Economic attacks

    Sandwichable flows, liquidation griefing and MEV exposure in protocol design.

Validation

Nothing is reported until it is proven.

  1. Step 1 / 3

    Fork the chain

    Opsec forks mainnet or your target L2 at a recent block with real balances and integrations.

  2. Step 2 / 3

    Write the exploit

    The agent composes an attacker contract and transaction sequence against the forked state.

  3. Step 3 / 3

    Measure the loss

    Findings report the value that moves, the preconditions and the block it was proven at.

Example finding

What lands in your queue.

Each finding carries the exploit path the validator walked and the repair it verified.

TSR-2291vault-corecontracts/LendingPool.sol
Critical

Reentrancy in withdraw()

SWC-107 · Smart contract agent · Exploitability 9.7

Exploit path

External call to msg.sender executes before the balance is updated, so a malicious receiver can re-enter withdraw() and drain the pool.

Why the fix works

Applies checks-effects-interactions and adds a reentrancy guard. The state update now happens before value leaves the contract.

Generated repair
function withdraw(uint256 amt) external {
function withdraw(uint256 amt) external nonReentrant {
require(balances[msg.sender] >= amt);
balances[msg.sender] -= amt;
(bool ok, ) = msg.sender.call{value: amt}("");
require(ok, "transfer failed");
balances[msg.sender] -= amt;
}
  • Exploit no longer reproduces on fork
  • Existing test suite passes (212)
  • Gas delta +2.1%

See what's exploitable in your environment.

Opsec is available to a limited number of security teams. Request access and we'll scope a private deployment with you.