Security
Try to break it
En esta página
Every claim in the threat model has been attacked, and the output of each attack is saved in this repository as text. Text is something you have to take our word for. This page does not ask you to: press a button and the attack is sent to the deployed contracts on Monad mainnet while you watch, and the refusal that comes back is the contract's own.
Nothing here can change anything. Each row is an eth_call, which is the question
"what would happen if this address sent this" rather than the sending of it. The
node runs the same bytecode a transaction would run, against the same state, and
throws the result away at the end. The only thing skipped is the commit, which is
also the only thing that would cost gas or need a key. That is why a call can be
sent as the burn address, 0x00...dEaD, which nobody has ever held a key for: the
refusal proves the rule is about who is asking, and no wallet is involved at any
point.
The last row is the control. It is the first row's call sent by the wallet that really does hold that passport, and it has to go through. A contract that refuses everything has proved nothing in particular, so the twelve rows are only worth reading together.
read only, on Monad mainnet
Twelve attacks.
Watch them refused.
Each row is sent as the attacker, straight from this page to the deployed contracts. An eth_call runs the same code a transaction runs and keeps none of it, so there is no wallet, no gas and nothing to sign.
0refused
of twelve
nothing has been sent yet
Speak for a passport you do not hold
MoolamConsent.setConsent sent as 0x00000000…00dEaD
pinned by MoolamConsent.t.sol::test_aStrangerCannotSpeakForAPassport, saved in consent-attacks.txt
not asked yet
the saved run answered NotPassportHolder
Ask to be asked first, and leave the conditions blank
MoolamConsent.setConsent sent as 0x85a88Ca8…A139a6
pinned by MoolamConsent.t.sol::test_aConstrainedFieldNeedsItsText, saved in consent-attacks.txt
not asked yet
the saved run answered ConstraintInfoRequired
Hide a line break inside the conditions
MoolamConsent.setConsent sent as 0x85a88Ca8…A139a6
pinned by MoolamConsent.t.sol::test_textWithAByteOutsidePrintableAsciiIsRefusedWithItsPosition, saved in consent-attacks.txt
not asked yet
the saved run answered ConstraintInfoNotPrintable
Write 257 bytes of conditions, one byte past the limit
MoolamConsent.setConsent sent as 0x85a88Ca8…A139a6
pinned by MoolamConsent.t.sol::test_textOneByteTooLongIsRefused, saved in consent-attacks.txt
not asked yet
the saved run answered ConstraintInfoTooLong
State for 33 passports in one call, one past the cap
MoolamConsent.setConsentBatch sent as 0x85a88Ca8…A139a6
pinned by MoolamConsent.t.sol::test_aBatchOfThirtyThreeIsRefused, saved in consent-attacks.txt
not asked yet
the saved run answered BatchTooLarge
Send a batch of nothing, which would look like a statement and change nothing
MoolamConsent.setConsentBatch sent as 0x85a88Ca8…A139a6
pinned by MoolamConsent.t.sol::test_anEmptyBatchIsRefused, saved in consent-attacks.txt
not asked yet
the saved run answered EmptyBatch
Send the consent register one wei of MON
MoolamConsent (a plain transfer, no function) sent as 0x85a88Ca8…A139a6
pinned by MoolamConsent.t.sol::test_thereIsNoWayToSendMonToThisContract, saved in consent-attacks.txt
not asked yet
the saved run got a revert with no data
Hang an edit off a passport somebody else holds
MoolamRegistry.appendEdit sent as 0xC5ead1E4…0b6Ef7
pinned by MoolamRegistry.t.sol::test_appendEditRejectsSomeoneWhoDoesNotHoldTheParent, saved in edit-by-non-owner.txt
not asked yet
the saved run answered NotParentOwner
Write a verification result without being a listed receiver
MoolamRegistry.attest sent as 0xC5ead1E4…0b6Ef7
pinned by MoolamRegistry.t.sol::test_attestRejectsAnAddressThePolicyDoesNotList, saved in attest-from-stranger.txt
not asked yet
the saved run answered NotReceiver
Deliver a well formed Chainlink report from the wrong sender
SimulationReceiver.onReport sent as 0xC5ead1E4…0b6Ef7
pinned by SimulationReceiver.t.sol::test_theSendingWalletCannotSkipTheForwarder, saved in report-from-fake-forwarder.txt
not asked yet
the saved run answered InvalidSender
Register a picture with a deadline that passed a minute ago
MoolamRegistry.register sent as 0x559F357a…15F67c
pinned by MoolamRegistry.t.sol::test_registerRejectsAPassedDeadline, saved in expired-deadline.txt
not asked yet
the saved run answered SignatureExpired
The same statement as the first row, sent by the wallet that does hold the passportcontrol
MoolamConsent.setConsent sent as 0x85a88Ca8…A139a6
pinned by MoolamConsent.t.sol::test_theHolderStatesWhatAiMayDoAndItReadsBack, saved in consent-attacks.txt
the control, not asked yet
the saved run went through with no revert
Where these came from
None of these attacks was invented for this screen. Each row names the transcript
it was taken from and the Foundry test that pins the same rule. The transcripts
under docs/security/attacks/ hold the whole session for each one: the call, the
address it was sent from and the error name. The twelve written by npm run prove
carry one thing this page cannot, the hash of the same attack sent as a real
transaction and reverted on Monad, as in
edit-by-non-owner.txt. The refusals from the
consent register were run by hand with cast call, and every command as it was
typed is in proofs/consent-attacks.txt.
What this page does not cover is an attack nobody thought of. It is the list from the threat model, written by the people who built the thing, and no third party has audited it.