Repository navigation
v0.7.0: a third reading of the access risk
Quorum had two readings of unguarded-state-write, and both judge a function by how it is written: whether it carries a modifier, and whether the variable it writes carries a privileged-looking name. Recent Solidity writes last_gauge and _validatorsMap, not feeRate, so on bench/MODERN.md that pair corroborated nothing and recall there was 0%. The last release ended by saying a genuinely different second reading was needed and was not designed yet. This is it.
consistency-lens asks the contract instead of the spelling. If every other externally callable function that writes a variable agrees on a modifier, and this one carries no guard at all, that disagreement is the evidence.
Three rules narrow it, and each came from opening a false confirmation and finding a reason for it:
- a one-shot initializer is guarded by being one-shot, because after deployment nobody can call it;
- a function that tests its own caller is not missing a guard, it is guarding differently;
- the caller has to be able to reach the write, by choosing either the value or the slot it goes to.
Carrying a different guard is not enough to be sighted. An admin setter beside a sibling that checks the caller in its own body is guarded, only differently, and reading that as a finding was noise on every corpus here.
Measured on all three, before and after, with the before files kept in bench/history:
- SmartBugs-curated: precision 49% to 48%, recall 63% to 64%, and one more labelled target confirmed, the owner change in multiowned_vulnerable.sol.
- DeFiVulnLabs, held out: unchanged at 62% precision and 50% recall, the same eight confirmations.
- Recent audit contests: recall 0% to 29%. Two real High severity findings confirmed, ServiceNft.updateImpact and AgentNftV2.addValidator in the Virtuals Protocol contest.
All 40 confirmations on that corpus were read by hand. Thirty-eight are false, and bench/MODERN.md names the four shapes they fall into: a write-once create on a fresh id, an in-body check the modifier reading cannot see, a caller writing their own row, and a value no caller can influence. The first and the last are the two worth a rule next, and they will be built against a labelled corpus before they are measured there.
The cost is written in the same file. This lens was developed against bench/MODERN.md, so that corpus is no longer held out for the access risk, and its 29% is not a measurement on unseen code. DeFiVulnLabs is now the only corpus no lens has ever been tuned against.
The package also reports its own version again. pyproject, quorum/init and the SARIF exporter all still said 0.1.0, six releases after that stopped being true.
81 tests.