Plainsign

Read before
you sign.

Your wallet shows you a sentence. The transaction is something else.

Plainsign simulates a transaction before you approve it and says what it does in words you already know: what leaves your wallet now, what someone can take later, and who ends up in control.

It never holds keys, never signs, never sends. It cannot move your money.

Bybit, 21 February 2025

Compromised interface displayed a routine transfer; the payload replaced the wallet's logic

Source NCC Group technical analysis; DFNS breakdown; Bybit incident timeline. Not published, so not modelled: Cold wallet balance at signing time is public (401,347 ETH) but is not part of this transaction's diff, so it is not modelled as a balance change.

What your wallet shows
Transaction request · Ethereum
Send 30,000 ETH to the warm wallet
To 0x1Db92e2EeBC8E0c075a02BeA49a2935BcD2dFCF4
Function execTransaction(...)
Fee Network fee applies
Confirm
What it actually does

Do not sign this.

Control of the cold wallet passes to someone else.

Immediately
  • Nothing leaves your wallet.
Afterwards
  • 0x4766…86e2, an attacker-controlled contract takes control of the cold wallet.

This changes who controls the contract

The implementation the wallet runs on the cold wallet changes from the audited Safe logic to 0x4766…86e2, an attacker-controlled contract. Afterwards, control over the funds held there belongs to someone else, and no further signature from you is needed.

What to do: Do not sign until the new controller is independently confirmed.

What you were shown is not what this does

Your wallet described this as "Send 30,000 ETH to the warm wallet". Simulating it shows that it also grants permissions or hands over control. The screen is not the transaction.

What to do: Trust the simulated result over the description.

This contract was created very recently

The contract at 0x9622…7242 was deployed 2 days ago. Draining campaigns run on contracts only days old. The established protocol you were looking for is not new.

What to do: Check the address against the project's own documentation.

Nobody can read what this contract does

The source code for 0x9622…7242 has not been published, so its behaviour cannot be checked by you or anyone else.

What to do
  1. Do not sign until the new controller is independently confirmed.
  2. Trust the simulated result over the description.
  3. Check the address against the project's own documentation.

0xb0b8…40c7, 14 October 2024

Off-chain permit signature; no gas, no entry in transaction history

Source PeckShield alert; Arkham attribution to Inferno Drainer. Not published, so not modelled: The exact wording the wallet displayed was not published; 'Signature request' is the generic label wallets use. Contract age of the spender was not reported.

What your wallet shows
Signature request · Ethereum
Signature request
To the address labelled Fake_Phishing442846
Function permit(...)
Fee No network fee
Confirm
What it actually does

Do not sign this.

An address later reported as a phishing address gains the right to take your PEPE whenever they choose.

Immediately
  • Nothing leaves your wallet.
Afterwards
  • an address later reported as a phishing address can take unlimited PEPE at any time from now on, without asking you again.

You are granting unlimited, open-ended permission

an address later reported as a phishing address will be able to move all of your PEPE, now and in the future. It does not expire and does not ask again. It stays active until you revoke it.

What to do: Approve only the amount you are spending right now. If the site will not let you, that is a reason to leave, not to sign.

This is a signature, not a transaction — and it still moves money

It costs no gas and will not show up in your transaction history, which is exactly why it looks harmless. It authorises someone to take your tokens later, without asking you again.

What to do: Treat a free signature with the same suspicion as a payment. Sign-in requests never need permission over your tokens.

This address has been publicly reported

the address labelled Fake_Phishing442846 is listed as malicious: labelled Fake_Phishing442846 and linked to a $32M drain two weeks earlier.

What to do: Do not sign. Close the page you came from.

Your wallet is not telling you what this does

The request is labelled "Signature request" and nothing more, yet it hands over control of your tokens. A request that will not say what it does is not one you can judge from the screen.

What to do: Read the effects below instead of the label, and sign nothing you cannot restate in your own words.

Nobody can read what this contract does

The source code for the address labelled Fake_Phishing442846 has not been published, so its behaviour cannot be checked by you or anyone else.

What to do
  1. Approve only the amount you are spending right now. If the site will not let you, that is a reason to leave, not to sign.
  2. Treat a free signature with the same suspicion as a payment. Sign-in requests never need permission over your tokens.
  3. Do not sign. Close the page you came from.
  4. Read the effects below instead of the label, and sign nothing you cannot restate in your own words.

12,083 spWETH, 28 September 2024

Permit phishing against a single large holder

Source PeckShield; reporting on the Inferno Drainer campaign. Not published, so not modelled: Wallet display wording and spender contract age were not published.

What your wallet shows
Signature request · Ethereum
Signature request
To the spender contract used in the campaign
Function permit(...)
Fee No network fee
Confirm
What it actually does

Do not sign this.

An unnamed address gains the right to take your spWETH whenever they choose.

Immediately
  • Nothing leaves your wallet.
Afterwards
  • an unnamed address can take unlimited spWETH at any time from now on, without asking you again.

You are granting unlimited, open-ended permission

an unnamed address will be able to move all of your spWETH, now and in the future. It does not expire and does not ask again. It stays active until you revoke it.

What to do: Approve only the amount you are spending right now. If the site will not let you, that is a reason to leave, not to sign.

This is a signature, not a transaction — and it still moves money

It costs no gas and will not show up in your transaction history, which is exactly why it looks harmless. It authorises someone to take your tokens later, without asking you again.

What to do: Treat a free signature with the same suspicion as a payment. Sign-in requests never need permission over your tokens.

Your wallet is not telling you what this does

The request is labelled "Signature request" and nothing more, yet it hands over control of your tokens. A request that will not say what it does is not one you can judge from the screen.

What to do: Read the effects below instead of the label, and sign nothing you cannot restate in your own words.

Nobody can read what this contract does

The source code for the spender contract used in the campaign has not been published, so its behaviour cannot be checked by you or anyone else.

What to do
  1. Approve only the amount you are spending right now. If the site will not let you, that is a reason to leave, not to sign.
  2. Treat a free signature with the same suspicion as a payment. Sign-in requests never need permission over your tokens.
  3. Read the effects below instead of the label, and sign nothing you cannot restate in your own words.

Transfer to an address that does not exist yet

Drainer sends funds to a precomputed address, deploying the contract afterwards

Source Check Point Research, Inferno Drainer analysis. Not published, so not modelled: Amount is illustrative; the technique is what is documented.

What your wallet shows
Transaction request · Ethereum
Send 4,200 USDC
To the destination address
Function transfer(address,uint256)
Fee Network fee applies
Confirm
What it actually does

Stop and check this.

4,200 USDC goes to an address you have not used before.

Immediately
  • 4,200 USDC leaves your wallet.

Nothing exists at this address yet

There is no contract and no history at the destination address. A destination can be calculated in advance and the code put there after you send, which is a known way of staying invisible to checks that ask how old a contract is.

What to do: Confirm the address from the project's own site before sending.

This moves 95% of your USDC

Transactions that empty a balance are worth a second look, because there is nothing left to recover from if it is wrong.

What to do: Send a small test amount first and confirm it arrives.

What to do
  1. Confirm the address from the project's own site before sending.
  2. Send a small test amount first and confirm it arrives.

An ordinary payment

Nothing wrong — included deliberately, to prove the tool stays quiet

Source Constructed.

What your wallet shows
Transaction request · Base
Send 50 USDC
To 0x742d35cc6634c0532925a3b844bc454e4438f44e
Function transfer(address,uint256)
Fee Network fee applies
Confirm
What it actually does

Nothing dangerous found.

50 USDC goes to 0x742d…f44e.

Immediately
  • 50 USDC leaves your wallet.
Reconstructed from public post-mortems

Every reading above came out of the tool.

Each case is rebuilt from published incident analysis, with the source named. Where a detail was never made public, it is left out rather than invented. The page is generated by the same code that runs in the command line, so nothing here is a mock-up written to look convincing.

Running the engine against these cases changed it. Two rules exist only because real incidents defeated the ones written first: wallets in the permit drains displayed no claim at all rather than a false one, and one campaign sends funds to an address whose contract is deployed afterwards, so every check asking how old a contract is stayed silent.

Still missing: decoding a transaction from raw data, and simulating it. Until those land, Plainsign reasons correctly about effects that something else has to supply.

Free and open source under the MIT licence. No token, no account, no tracking. Plainsign never holds keys, never signs and never broadcasts.

A clean result is one input to your decision, not permission. Where data is missing, checks stay silent — and silence is not a clean bill of health.