Install
$ agentstack add skill-omermaksutii-rugproof-cross-contract-state ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Cross-contract state consistency detection
When this applies
Trigger on any of:
- A value (price, total supply, share rate, debt) lives in contract A but is read by B
- Cached/mirrored state (
cachedRate,lastTotalAssets) that must be refreshed - Multi-contract operations that mutate several contracts non-atomically
- Modules/plugins/hooks that read core state mid-update (read-during-callback)
- Proxy + implementation, or vault + strategy, or controller + market splits
- Accounting assuming "A and B are always in sync"
Detection patterns
Stale read of another contract's mid-update state (HIGH)
// Vault.deposit() transfers to Strategy, then:
uint256 tvl = strategy.totalAssets(); // ← strategy hasn't accounted the deposit yet
shares = amount * totalSupply / tvl; // wrong denominator
Signal: B reads A while A's update is incomplete (or vice versa). Share/price math uses a denominator that's about to change, letting an attacker mint mispriced shares. This is the read-only-reentrancy family generalized to ordinary call ordering.
Cached value drift (HIGH)
uint256 public cachedPrice; // updated by poke()
function valueOf(uint256 amt) external view returns (uint256) {
return amt * cachedPrice / 1e18; // ← may be hours stale
}
Signal: a mirrored value with no freshness guarantee or no atomic refresh-before-use. Trades/loans price off a cache that diverged from the source contract.
Non-atomic multi-contract update (HIGH)
registry.setActive(id, true);
// external call here can observe registry=active but vault=uninitialized
vault.initialize(id);
Signal: state spread across contracts is updated in sequence; a reentrant or interleaved call observes a half-applied transaction (one contract updated, the other not). Invariants that span both contracts are temporarily violated.
Shared dependency divergence (MEDIUM / HIGH)
Two contracts both read the same oracle/token but at different blocks or via different cached copies, then reconcile assuming equality. Signal: assert(A.totalSupply() == B.mirroredSupply())-style assumptions with independent update paths.
Read-during-callback (HIGH)
A hook/plugin invoked mid-operation calls back and reads the core contract's not-yet-finalized accounting — the Curve/Balancer read-only reentrancy shape, but also plain composability (e.g. an ERC-4626 vault read by a money-market during the vault's own deposit).
Severity rubric
| Pattern | Severity | Notes | |---|---|---| | Stale cross-contract read in share/price math | High | Mispriced mint/redeem | | Read-during-callback of unfinalized state | High | Read-only reentrancy class | | Non-atomic multi-contract invariant break | High | Half-applied state observable | | Cached value drift used for valuation | High | Stale pricing | | Synchronized-state assumption across modules | Medium | Reconciliation error |
Remediation patterns
- Single source of truth — derive values from one authoritative contract at read time; avoid mirrored copies, or make the mirror push-updated atomically in the same tx.
- Update-then-read ordering — ensure A finalizes accounting before B reads; apply CEI across the call boundary, not just within a function.
- Atomic multi-contract updates — batch via a single entrypoint / multicall that completes all writes before any external observation; guard with a system-wide reentrancy lock.
- Freshness gates on caches —
require(block.timestamp - lastUpdate <= maxAge)or refresh-on-read. - Reentrancy-guard the read path too (Balancer
ensureNotInVaultContext/ Curve lock) when callbacks can observe state.
False-positive notes
- A mirror that is push-updated atomically in the same transaction as its source is consistent — don't flag.
- Independent contracts that never reconcile or compare state aren't subject to this; the risk needs a shared invariant.
- Eventually-consistent designs that explicitly tolerate drift (and bound it) are by-design — note the assumption.
Related
- [[reentrancy]] — read-only reentrancy is the callback variant of this
- [[oracle-redundancy]] — shared feed staleness/divergence
- [[storage-layout]] — proxy/implementation storage must also stay consistent
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: omermaksutii
- Source: omermaksutii/RugProof
- License: MIT
- Homepage: https://omermaksutii.github.io/RugProof
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.