Presign

Know exactly what you sign.

Checking… Connect wallet

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

    CRITICAL

    An 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

    CRITICAL

    A Squads create, approve or execute instruction is signed inside a durable-nonce transaction: the signature never expires.

  • MS_VOTE_SIGNED_IN_ADVANCE

    HIGH

    A 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

    CRITICAL

    A 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 raised

    The proposal changes the approval threshold.

  • MS_AUTHORITY_TO_SINGLE_KEY

    HIGH

    An authority goes to one member's key, which can then act without a vote.

  • MS_AUTHORITY_REMOVED

    HIGH

    An authority is removed permanently.

  • MS_PROGRAM_UPGRADE

    HIGH

    A program's code is replaced.

  • MS_PROGRAM_CLOSE

    HIGH

    A program or program buffer is closed.

  • MS_ACCOUNT_REASSIGN

    HIGH

    An account is reassigned to another owner program.

  • MS_ADMIN_CHANGE_UNKNOWN_TARGET

    HIGH

    An instruction named like an authority change (from the program's IDL) whose new holder cannot be identified.

  • MS_PAYLOAD_UNVERIFIED

    HIGH

    The 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 otherwise

    The proposal changes the time lock.

  • MS_NO_TIME_LOCK

    HIGH with a privileged action · MEDIUM otherwise

    The proposal can execute the moment its threshold is reached.

  • MS_MINORITY_THRESHOLD

    MEDIUM with a privileged action · LOW otherwise

    Fewer than half of the voting members can pass it.

  • MS_ADMIN_ACTION

    MEDIUM

    An administrative instruction (pause, fees, oracle, config…), or a call the vault signs as a program's admin.

  • MS_VAULT_OUTFLOW

    MEDIUM

    The simulated execution moves assets out of the vault.

  • MS_FOREIGN_SIGNER

    MEDIUM

    The vault transaction requires a signature the multisig cannot provide.

  • MS_CONTROLLED_MULTISIG

    MEDIUM

    A config authority can change the multisig without a vote.

  • MS_FINAL_APPROVAL

    MEDIUM

    Your approval is the one that makes the proposal executable.

  • MS_MEMBER_ADDED

    MEDIUM

    A member is added.

  • MS_MEMBER_REMOVED

    MEDIUM

    A member is removed.

  • MS_SPENDING_LIMIT_ADDED

    MEDIUM to any destination · LOW with a destination list

    Members may spend without a vote up to a limit.

  • MS_AUTHORITY_TO_GUARD

    LOW

    An authority goes to a Presign Guard whose proposer is this multisig's vault: still controlled, now delayed and vetoable.

  • MS_AUTHORITY_INTERNAL

    LOW

    An authority moves between addresses the multisig controls.

  • MS_PAYLOAD_PARTIAL

    LOW

    Some instructions could not be decoded (for example a program without a public IDL).

  • MS_CONFIG_MINOR

    LOW

    The rent collector changes or a spending limit is removed.

  • VAULT_TX_*

    as the transaction rule

    Transaction 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

    HIGH

    One signature is enough: a single member, or threshold 1 with several voters.

  • POSTURE_CONTROLLED

    HIGH

    A config authority can change members, threshold and time lock without a vote.

  • POSTURE_MINORITY_THRESHOLD

    MEDIUM

    A minority of voting members can pass any proposal.

  • POSTURE_NO_TIME_LOCK

    MEDIUM

    Approved proposals execute immediately.

  • POSTURE_NO_EXECUTOR

    LOW

    No 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

    HIGH

    The buffer with the new code could not be read.

  • UPGRADE_UNVERIFIED_CODE

    MEDIUM

    The new code is not a build the registry verified for this program.

  • UPGRADE_MATCHES_VERIFIED_BUILD

    LOW

    The 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 shrinks

    A scheduled change of the guard's own configuration weakens it — the first thing an attacker holding the proposer would schedule.

  • GUARD_ACTION_UNDECODED

    HIGH

    Part of a scheduled action could not be decoded.

  • GUARD_MS_*

    one level below the immediate rule

    A 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

    MEDIUM

    The delay has passed: anyone can execute the action now.

  • GUARD_SHORT_DELAY

    MEDIUM

    The guard's delay is under one hour.

  • GUARD_SINGLE_GUARDIAN

    MEDIUM

    Only one guardian can veto.

  • GUARD_UNVERIFIED

    MEDIUM

    The guard account could not be loaded, so its delay and guardians are unknown.

  • GUARD_CONFIG_CHANGE

    MEDIUM if the current setup is unknown · LOW otherwise

    A scheduled configuration change that weakens nothing (adds guardians, lengthens the delay).

  • GUARD_SCHEDULED

    LOW

    The proposal schedules actions through Presign Guard.

  • GUARD_ACTION_PENDING

    LOW

    The action is waiting and can still be vetoed.

  • GUARD_PROPOSER_IS_GUARDIAN

    LOW

    The 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>

    MEDIUM

    A 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

    CRITICAL

    Your wallet account is assigned to another program.

  • TX_TOKEN_ACCOUNT_OWNER_CHANGE

    CRITICAL

    Your token account gets a new owner.

  • TX_UNLIMITED_APPROVAL

    CRITICAL

    A delegate may spend an unlimited amount of your tokens.

  • TX_SOL_DRAIN

    CRITICAL

    Nearly all of your SOL leaves the wallet.

  • TX_MULTI_ASSET_DRAIN

    CRITICAL

    Several different tokens leave your wallet at once — a typical drainer pattern.

  • TX_UPGRADE_AUTHORITY_CHANGE

    CRITICAL to a new key · HIGH if removed

    A program's upgrade authority changes.

  • TX_TOKEN_APPROVAL

    HIGH

    A delegate may spend your tokens.

  • TX_UNEXPECTED_SOL_OUTFLOW

    HIGH

    More SOL leaves than the visible transfer instructions explain.

  • TX_UNEXPECTED_TOKEN_OUTFLOW

    HIGH

    Tokens leave through a program call that is not a visible transfer.

  • TX_FULL_BALANCE_TRANSFER

    HIGH

    Your entire balance of a token moves.

  • TX_CLOSE_AUTHORITY_CHANGE

    HIGH

    A close authority is transferred.

  • TX_NONCE_AUTHORITY_CHANGE

    HIGH

    A nonce account's authority is transferred.

  • TX_CLOSE_RENT_TO_OTHER

    HIGH

    An account is closed and its rent goes to someone else.

  • TX_CPI_GUARD_DISABLED_WITH_UNKNOWN_PROGRAM

    HIGH

    Token-2022 CPI Guard is disabled in the same transaction as an unverified program.

  • TX_SOL_OUTFLOW

    MEDIUM

    SOL is sent to a destination.

  • TX_TOKEN_OUTFLOW

    MEDIUM

    Tokens are sent or burned.

  • TX_MINT_AUTHORITY_CHANGE

    MEDIUM

    A mint or freeze authority changes.

  • TX_DURABLE_NONCE

    MEDIUM

    The transaction uses a durable nonce and does not expire with its blockhash.

  • TX_CPI_GUARD_DISABLED

    MEDIUM

    Token-2022 CPI Guard is disabled.

  • TX_MEMO_SUSPICIOUS_LINK

    MEDIUM

    A memo contains a link with phishing traits (links are always shown defanged).

  • TX_UNKNOWN_PROGRAM

    LOW

    An unverified program is called.

  • TX_SIMULATION_FAILED

    LOW

    The simulation fails; balance changes cannot be observed.

  • TX_RENT_DEPOSIT

    LOW

    SOL goes into new accounts as their rent-exempt deposit.

  • TX_TOKEN2022_CONFIDENTIAL

    LOW

    A confidential transfer hides amounts.

  • TX_EXCESSIVE_PRIORITY_FEE

    MEDIUM ≥ 0.01 SOL · HIGH ≥ 0.1 SOL · CRITICAL ≥ half the wallet's SOL

    The priority fee (compute unit price × limit) the wallet pays is inflated — a drain that looks like a fee.

  • TX_STAKE_WITHDRAW_AUTHORITY_CHANGE

    CRITICAL

    The 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

    HIGH

    The stake authority of a stake account held by the wallet moves to another address.

  • TX_STAKE_WITHDRAW_TO_OTHER

    HIGH

    SOL is withdrawn from a stake account the wallet controls to another address.

  • TX_STAKE_LOCKUP_CHANGE

    MEDIUM

    The lockup of a stake account the wallet controls changes.

  • TX_CNFT_TRANSFER

    HIGH

    A compressed NFT (Bubblegum) owned or delegated to the wallet is transferred to another address — invisible to token-balance simulation.

  • TX_CNFT_DRAIN

    CRITICAL

    Two or more compressed NFTs leave the wallet in one transaction.

  • TX_CNFT_DELEGATE

    HIGH

    Another address becomes the delegate of a compressed NFT the wallet owns.

  • TX_CNFT_BURN

    MEDIUM

    A compressed NFT the wallet owns is burned.

  • TX_CNFT_UNDECODED

    HIGH

    A Bubblegum v2 transfer / delegate / burn involves the wallet; identified, but its recipient is not decoded.

  • TX_NFT_PROGRAM_UNDECODED

    MEDIUM

    A Metaplex Core instruction involves the wallet: NFT ownership changes are not token balances and are not decoded.

  • TX_PROGRAM_UPGRADE

    HIGH

    The wallet, as upgrade authority, replaces a program's code.

  • TX_PROGRAM_CLOSE

    HIGH

    The wallet, as authority, closes a program or buffer permanently.

  • TX_WALLET_ALLOCATE

    HIGH

    The wallet account itself would get data space and may become unusable.

  • TX_MINT_TO_OTHER

    MEDIUM

    Tokens are minted with the wallet's mint authority to an account it does not own.

  • TX_UNKNOWN_PROGRAM_DURABLE_NONCE

    HIGH

    A 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

    MEDIUM

    An 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

    LOW

    Other transactions changed your SOL balance during the simulation; only outflow they cannot explain is treated as unexpected.

  • TX_TOKEN_CHANGE_UNCERTAIN

    LOW

    Other 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

    CRITICAL

    The bytes presented as a message are a valid Solana transaction message; signing them can authorize that transaction.

  • MSG_HIDDEN_CHARACTERS

    HIGH

    The message contains zero-width or direction-changing characters that hide or reorder text.

  • MSG_SECRET_REQUEST

    HIGH

    The message mentions a seed phrase, recovery phrase or private key.

  • MSG_DOMAIN_MISMATCH

    HIGH

    The 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

    MEDIUM

    The message uses transfer, approval or permission language the requesting service may treat as your authorization.

  • MSG_PROMPT_INJECTION

    MEDIUM

    The message contains wording aimed at manipulating automated reviewers.

  • MSG_OPAQUE_DATA

    MEDIUM

    The 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

    LOW

    A sign-in message has no one-time nonce or no timestamp, so the signature could be reused.

  • DOMAIN_<pattern>

    LOW–HIGH

    The 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

    HIGH

    The connecting application uses plain http (outside local development).

  • PRESIGN_SOL_EXCEEDS_DECLARED

    HIGH

    The simulation moves more SOL out of the wallet than the requesting application declared (network fee excluded).

  • PRESIGN_TOKEN_EXCEEDS_DECLARED:<mint>

    HIGH

    The simulation moves more of a token out of the wallet than the application declared.

  • PRESIGN_UNDECLARED_TOKEN_OUTFLOW:<mint>

    HIGH

    The 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

    MEDIUM

    The 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

    HIGH

    The connecting application's address is not a valid https:// URL; the connection request is refused.

  • DOMAIN_LOCAL_DEVELOPMENT

    LOW

    The 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).