Rule catalog
Presign's verdicts come from these 111 rules — no model decides. Every signal cites its evidence (instruction, account, IDL field or simulation), the verdict is the highest severity found, and missing data can never produce "no risk". The code is what the API, MCP tools and Watchtower return; a suffix (instruction index, mint, account) is added when a rule fires more than once.
Multisig proposals
What a Squads proposal (or a signature on one) would do, from the vault's point of view.
MS_AUTHORITY_LEAVES_MULTISIG
CRITICALAn admin, upgrade, token or config authority goes to an address that is not the multisig, one of its vaults, a member, or the multisig's own Presign Guard.
MS_DURABLE_NONCE_GOVERNANCE
CRITICALA Squads create, approve or execute instruction is signed inside a durable-nonce transaction: the signature never expires.
MS_VOTE_SIGNED_IN_ADVANCE
HIGHA create, approve or execute of this proposal already on chain landed inside a durable-nonce transaction: it may have been signed days or weeks before (the Drift takeover pattern).
MS_CONFIG_AUTHORITY_SET
CRITICALA single key becomes the multisig's config authority and could change members and threshold without a vote.
MS_THRESHOLD_CHANGE
CRITICAL if set to 1 · HIGH if lowered · LOW if raisedThe proposal changes the approval threshold.
MS_AUTHORITY_TO_SINGLE_KEY
HIGHAn authority goes to one member's key, which can then act without a vote.
MS_AUTHORITY_REMOVED
HIGHAn authority is removed permanently.
MS_PROGRAM_UPGRADE
HIGHA program's code is replaced.
MS_PROGRAM_CLOSE
HIGHA program or program buffer is closed.
MS_ACCOUNT_REASSIGN
HIGHAn account is reassigned to another owner program.
MS_ADMIN_CHANGE_UNKNOWN_TARGET
HIGHAn instruction named like an authority change (from the program's IDL) whose new holder cannot be identified.
MS_PAYLOAD_UNVERIFIED
HIGHThe proposal's contents could not be loaded or decoded; it can never be reported as no risk.
MS_TIME_LOCK_CHANGE
HIGH if removed or shortened · LOW otherwiseThe proposal changes the time lock.
MS_NO_TIME_LOCK
HIGH with a privileged action · MEDIUM otherwiseThe proposal can execute the moment its threshold is reached.
MS_MINORITY_THRESHOLD
MEDIUM with a privileged action · LOW otherwiseFewer than half of the voting members can pass it.
MS_ADMIN_ACTION
MEDIUMAn administrative instruction (pause, fees, oracle, config…), or a call the vault signs as a program's admin.
MS_VAULT_OUTFLOW
MEDIUMThe simulated execution moves assets out of the vault.
MS_FOREIGN_SIGNER
MEDIUMThe vault transaction requires a signature the multisig cannot provide.
MS_CONTROLLED_MULTISIG
MEDIUMA config authority can change the multisig without a vote.
MS_FINAL_APPROVAL
MEDIUMYour approval is the one that makes the proposal executable.
MS_MEMBER_ADDED
MEDIUMA member is added.
MS_MEMBER_REMOVED
MEDIUMA member is removed.
MS_SPENDING_LIMIT_ADDED
MEDIUM to any destination · LOW with a destination listMembers may spend without a vote up to a limit.
MS_AUTHORITY_TO_GUARD
LOWAn authority goes to a Presign Guard whose proposer is this multisig's vault: still controlled, now delayed and vetoable.
MS_AUTHORITY_INTERNAL
LOWAn authority moves between addresses the multisig controls.
MS_PAYLOAD_PARTIAL
LOWSome instructions could not be decoded (for example a program without a public IDL).
MS_CONFIG_MINOR
LOWThe rent collector changes or a spending limit is removed.
VAULT_TX_*
as the transaction ruleTransaction rules (drains, approvals, owner changes…) applied to the vault's simulated execution.
Multisig setup
Standing risks of a multisig's configuration, independent of any proposal.
POSTURE_SINGLE_SIGNATURE
HIGHOne signature is enough: a single member, or threshold 1 with several voters.
POSTURE_CONTROLLED
HIGHA config authority can change members, threshold and time lock without a vote.
POSTURE_MINORITY_THRESHOLD
MEDIUMA minority of voting members can pass any proposal.
POSTURE_NO_TIME_LOCK
MEDIUMApproved proposals execute immediately.
POSTURE_NO_EXECUTOR
LOWNo member has the Execute permission.
Program upgrades
The code a proposal would deploy, hashed like solana-verify and compared with the OtterSec verified-builds registry.
UPGRADE_CODE_UNAVAILABLE
HIGHThe buffer with the new code could not be read.
UPGRADE_UNVERIFIED_CODE
MEDIUMThe new code is not a build the registry verified for this program.
UPGRADE_MATCHES_VERIFIED_BUILD
LOWThe new code is exactly a verified build (source repository and commit shown).
Presign Guard
Actions scheduled through the on-chain guard (delay + single-guardian veto) and the guard's own setup.
GUARD_CONFIG_WEAKENED
CRITICAL if the proposer leaves or every guardian is replaced · HIGH if guardians are removed or the delay shrinksA scheduled change of the guard's own configuration weakens it — the first thing an attacker holding the proposer would schedule.
GUARD_ACTION_UNDECODED
HIGHPart of a scheduled action could not be decoded.
GUARD_MS_*
one level below the immediate ruleA privileged action scheduled through a guard whose delay and veto were verified on-chain; unchanged severity when the guard cannot be verified.
GUARD_ACTION_EXECUTABLE
MEDIUMThe delay has passed: anyone can execute the action now.
GUARD_SHORT_DELAY
MEDIUMThe guard's delay is under one hour.
GUARD_SINGLE_GUARDIAN
MEDIUMOnly one guardian can veto.
GUARD_UNVERIFIED
MEDIUMThe guard account could not be loaded, so its delay and guardians are unknown.
GUARD_CONFIG_CHANGE
MEDIUM if the current setup is unknown · LOW otherwiseA scheduled configuration change that weakens nothing (adds guardians, lengthens the delay).
GUARD_SCHEDULED
LOWThe proposal schedules actions through Presign Guard.
GUARD_ACTION_PENDING
LOWThe action is waiting and can still be vetoed.
GUARD_PROPOSER_IS_GUARDIAN
LOWThe proposer is also a guardian.
Team policy
Your own rules, when a policy is supplied. A policy only adds signals.
POLICY_<rule>
the policy's severity (HIGH by default)A rule of the supplied team policy is broken.
POLICY_UNVERIFIED_<rule>
MEDIUMA rule could not be checked: contents not decoded, not simulated, or an account not loaded.
Transactions
Any transaction before it is signed: decoded instructions and simulated balance changes of the signer.
TX_WALLET_OWNER_REASSIGN
CRITICALYour wallet account is assigned to another program.
TX_TOKEN_ACCOUNT_OWNER_CHANGE
CRITICALYour token account gets a new owner.
TX_UNLIMITED_APPROVAL
CRITICALA delegate may spend an unlimited amount of your tokens.
TX_SOL_DRAIN
CRITICALNearly all of your SOL leaves the wallet.
TX_MULTI_ASSET_DRAIN
CRITICALSeveral different tokens leave your wallet at once — a typical drainer pattern.
TX_UPGRADE_AUTHORITY_CHANGE
CRITICAL to a new key · HIGH if removedA program's upgrade authority changes.
TX_TOKEN_APPROVAL
HIGHA delegate may spend your tokens.
TX_UNEXPECTED_SOL_OUTFLOW
HIGHMore SOL leaves than the visible transfer instructions explain.
TX_UNEXPECTED_TOKEN_OUTFLOW
HIGHTokens leave through a program call that is not a visible transfer.
TX_FULL_BALANCE_TRANSFER
HIGHYour entire balance of a token moves.
TX_CLOSE_AUTHORITY_CHANGE
HIGHA close authority is transferred.
TX_NONCE_AUTHORITY_CHANGE
HIGHA nonce account's authority is transferred.
TX_CLOSE_RENT_TO_OTHER
HIGHAn account is closed and its rent goes to someone else.
TX_CPI_GUARD_DISABLED_WITH_UNKNOWN_PROGRAM
HIGHToken-2022 CPI Guard is disabled in the same transaction as an unverified program.
TX_SOL_OUTFLOW
MEDIUMSOL is sent to a destination.
TX_TOKEN_OUTFLOW
MEDIUMTokens are sent or burned.
TX_MINT_AUTHORITY_CHANGE
MEDIUMA mint or freeze authority changes.
TX_DURABLE_NONCE
MEDIUMThe transaction uses a durable nonce and does not expire with its blockhash.
TX_CPI_GUARD_DISABLED
MEDIUMToken-2022 CPI Guard is disabled.
TX_MEMO_SUSPICIOUS_LINK
MEDIUMA memo contains a link with phishing traits (links are always shown defanged).
TX_UNKNOWN_PROGRAM
LOWAn unverified program is called.
TX_SIMULATION_FAILED
LOWThe simulation fails; balance changes cannot be observed.
TX_RENT_DEPOSIT
LOWSOL goes into new accounts as their rent-exempt deposit.
TX_TOKEN2022_CONFIDENTIAL
LOWA confidential transfer hides amounts.
TX_EXCESSIVE_PRIORITY_FEE
MEDIUM ≥ 0.01 SOL · HIGH ≥ 0.1 SOL · CRITICAL ≥ half the wallet's SOLThe priority fee (compute unit price × limit) the wallet pays is inflated — a drain that looks like a fee.
TX_STAKE_WITHDRAW_AUTHORITY_CHANGE
CRITICALThe withdraw authority of a stake account held by the wallet moves to another address (staked SOL is not in the wallet balance).
TX_STAKE_AUTHORITY_CHANGE
HIGHThe stake authority of a stake account held by the wallet moves to another address.
TX_STAKE_WITHDRAW_TO_OTHER
HIGHSOL is withdrawn from a stake account the wallet controls to another address.
TX_STAKE_LOCKUP_CHANGE
MEDIUMThe lockup of a stake account the wallet controls changes.
TX_CNFT_TRANSFER
HIGHA compressed NFT (Bubblegum) owned or delegated to the wallet is transferred to another address — invisible to token-balance simulation.
TX_CNFT_DRAIN
CRITICALTwo or more compressed NFTs leave the wallet in one transaction.
TX_CNFT_DELEGATE
HIGHAnother address becomes the delegate of a compressed NFT the wallet owns.
TX_CNFT_BURN
MEDIUMA compressed NFT the wallet owns is burned.
TX_CNFT_UNDECODED
HIGHA Bubblegum v2 transfer / delegate / burn involves the wallet; identified, but its recipient is not decoded.
TX_NFT_PROGRAM_UNDECODED
MEDIUMA Metaplex Core instruction involves the wallet: NFT ownership changes are not token balances and are not decoded.
TX_PROGRAM_UPGRADE
HIGHThe wallet, as upgrade authority, replaces a program's code.
TX_PROGRAM_CLOSE
HIGHThe wallet, as authority, closes a program or buffer permanently.
TX_WALLET_ALLOCATE
HIGHThe wallet account itself would get data space and may become unusable.
TX_MINT_TO_OTHER
MEDIUMTokens are minted with the wallet's mint authority to an account it does not own.
TX_UNKNOWN_PROGRAM_DURABLE_NONCE
HIGHA never-expiring (durable nonce) signature calls an unverified program: it can run later, when behavior may differ from today's simulation.
TX_SIMULATION_EVASION_RISK
MEDIUMAn unverified program gets the wallet's signature and write access to its token accounts but does nothing visible in the simulation — the pattern of drainers that detect simulations.
TX_SOL_CHANGE_UNCERTAIN
LOWOther transactions changed your SOL balance during the simulation; only outflow they cannot explain is treated as unexpected.
TX_TOKEN_CHANGE_UNCERTAIN
LOWOther transactions changed your token balance during the simulation; only outflow they cannot explain is treated as unexpected.
Messages & connections
Off-chain message signing requests and the application (domain) a wallet connects to, in Presign's pre-sign review.
MSG_IS_TRANSACTION
CRITICALThe bytes presented as a message are a valid Solana transaction message; signing them can authorize that transaction.
MSG_HIDDEN_CHARACTERS
HIGHThe message contains zero-width or direction-changing characters that hide or reorder text.
MSG_SECRET_REQUEST
HIGHThe message mentions a seed phrase, recovery phrase or private key.
MSG_DOMAIN_MISMATCH
HIGHThe message names a different website than the origin Presign verified for the request.
MSG_SUSPICIOUS_LINK
LOW–HIGH (link pattern level)A link in the message matches phishing patterns.
MSG_AUTHORIZATION_LANGUAGE
MEDIUMThe message uses transfer, approval or permission language the requesting service may treat as your authorization.
MSG_PROMPT_INJECTION
MEDIUMThe message contains wording aimed at manipulating automated reviewers.
MSG_OPAQUE_DATA
MEDIUMThe message contains a long encoded block (100+ characters of hex / base58 / base64) — a key, signature or payload the signer cannot read; the evidence notes when it decodes as a Solana transaction.
MSG_REPLAYABLE_LOGIN
LOWA sign-in message has no one-time nonce or no timestamp, so the signature could be reused.
DOMAIN_<pattern>
LOW–HIGHThe connecting application's address matches a phishing pattern (look-alike brand, punycode, shortener, raw IP, suspicious TLD, hidden characters, disguised destination…); an unknown domain is reported as unknown, never safe.
DOMAIN_NOT_HTTPS
HIGHThe connecting application uses plain http (outside local development).
PRESIGN_SOL_EXCEEDS_DECLARED
HIGHThe simulation moves more SOL out of the wallet than the requesting application declared (network fee excluded).
PRESIGN_TOKEN_EXCEEDS_DECLARED:<mint>
HIGHThe simulation moves more of a token out of the wallet than the application declared.
PRESIGN_UNDECLARED_TOKEN_OUTFLOW:<mint>
HIGHThe simulation moves a token out of the wallet that the application did not declare at all.
PRESIGN_RECEIVED_RISKY_TOKEN
HIGH(suffixed :<mint>) A token the simulation credits to the wallet has HIGH/CRITICAL token findings (freeze authority, permanent delegate, paused, default-frozen, RugCheck rugged…): a honeypot swap. A failed scan makes the analysis PARTIAL.
PRESIGN_POISONED_RECIPIENT
HIGH(suffixed :<address>) The wallet pays an address directly whose only earlier contact with it was unsolicited dust (≤ 0.001 SOL / 0.01 tokens, never signed by the wallet): the address-poisoning pattern. Checks the last 1,000 transactions; a failed lookup makes the analysis PARTIAL.
DOMAIN_NAME_IMPERSONATION
MEDIUMThe application's name claims a well-known brand (Phantom, Jupiter, Solflare…) but its domain is not one of that brand's known domains.
DOMAIN_INVALID
HIGHThe connecting application's address is not a valid https:// URL; the connection request is refused.
DOMAIN_LOCAL_DEVELOPMENT
LOWThe connecting application runs on this computer (localhost) over plain http.
The gate for automated signers follows the verdict: CRITICAL or HIGH → block; MEDIUM, unrated or incomplete → require human review; otherwise no known risk. Token and wallet-scanner rules are listed in the source (lib/security/rules).