torhaven the safety handbook

torhaven · Market safety · before you pay

Verify an onion address before you deposit, every single time (2026)

Most money lost on Tor is not lost to clever hacking. It is sent to the wrong address, one that looks almost exactly like the right one. This is the short routine that stops that, run once, every time, before anything moves.

7 min readLast verified: 24 August 2026torhaven · no ads · no affiliate

torhaven key takeaways

  • A deposit is irreversible, so the check happens before you pay, not after something looks wrong.
  • Read the address from a source you can verify, never from a link, a chat message or a search result.
  • Compare all 56 characters. A shared prefix means nothing, because attackers grind look-alikes on purpose.
  • Confirm the signature and the signing key's fingerprint before you trust the list the address came from.
  • If any single check fails, stop. There is no partial pass when money is about to move.
On this torhaven page

On this torhaven page

  1. Why a deposit is the moment to check
  2. The routine, step by step
  3. The decision, drawn out
  4. Red flags that end the check
  5. How a wrong address reaches you
  6. Comparing 56 characters
  7. Is the address even well-formed?
  8. Reading a gpg verification
  9. A worked example
  10. After the deposit
  11. Verify once vs. every time
  12. What the routine does not cover
  13. Mistakes that undo a check
  14. Where this fits torhaven
  15. Common questions
  16. Related guides

A deposit is the one action on Tor you cannot take back. Once coins leave your wallet they are gone, and if they went to a look-alike address there is no support desk and no chargeback. That is why the check belongs at the moment before you pay, when it can still change the outcome, and not five minutes later when you are wondering why nothing arrived. The routine below takes about a minute and it does not get easier to skip the more times you have gotten away with skipping it.

Why a deposit is the moment to check

Browsing a market on a slightly wrong mirror is annoying. Depositing to a slightly wrong address is expensive. The stakes are not the same, so the care you take should not be the same either. Treat reading pages as low risk and moving money as the point where the full check is not optional. A single verified habit at that one moment protects the only step that cannot be undone.

The routine, step by step

  1. Read the address from a signed source. Open a source of record you can verify and take the address from there. Do not use a link someone gave you, even a helpful one.
  2. Compare all 56 characters. A v3 onion is 56 characters before .onion. Check the whole string against the signed copy, start to finish.
  3. Confirm the signature and fingerprint. Verify the signature over the source, and match the signing key's fingerprint against a copy you got some other way.
  4. Copy the string by hand. Select it as text and paste it into Tor Browser yourself. Copying breaks the reflex of clicking whatever is in front of you.
  5. Deposit only if every check passed. If one did not, you stop. Nothing about being in a hurry changes that.

torhaven safety note

Keep the signed source in a bookmark you trust and open it fresh each time, rather than trusting a copy of the address you saved earlier. The point of the check is to notice when the right answer has changed, and a saved copy cannot tell you that.

The decision, drawn out

Every check is really a short series of yes-or-no questions, and any single no ends it. Seeing the shape of that decision makes it harder to talk yourself past a failed step.

Red flags that end the check

Some signs mean you stop without finishing the rest of the routine. A shortened link or a QR code hides the very thing you need to read. An address handed to you in a direct message, especially with a reason to hurry, is a classic setup. A source that cannot produce a valid signature is not a source you can act on, however official it looks.

torhaven warning

Urgency is the tell. Every scam that relies on a swapped address needs you to move before you check. A real service is not harmed by you taking a minute to confirm its address, so anyone pushing you past that step is telling you something about themselves.

Why a QR code is worse than a plain-text link

A QR code encodes the address in a form you cannot read by eye before scanning it, which removes the one step this entire routine is built around: comparing the full string yourself. A swapped address hidden inside a QR code is invisible until it is too late to matter. Insist on plain text, even if it means retyping a shortened process into a longer one.

What "an official source" actually needs to show

"Official" is not a feeling a page gives off through design polish or confident language; it is a specific, checkable claim — a signature that verifies against a key you already trust, from a channel you decided to trust before you needed it, not one a stranger just handed you. A page that looks professional and a page that is verifiable are two entirely different properties, and only the second one matters here.

How a wrong address actually reaches you

It is easier to keep a routine when you know what each step is for. The five steps above are not a ritual; each one blocks a specific, well-understood way that a substituted address gets in front of a reader. There are four such ways in common use, and they are worth naming separately because they fail in different places and are defeated by different steps.

1. A cloned page that is otherwise perfect

The cheapest attack does not touch cryptography at all. Someone copies a directory listing, a market's own landing page, or a helpful forum post; changes the addresses inside the copy; and then gets that copy in front of you — through a search result, a clearnet advert, a link pasted into a chat, or a domain one character away from the real one. Nothing is broken and nothing looks wrong, because everything on the page except the address is genuine. You simply read the wrong page. This is exactly what step one is for: once an address only counts when it arrives with a signature you can check, a clone has to forge the signature too, and forging a signature is a categorically harder problem than copying some HTML.

2. A ground look-alike address

An onion address is derived from a public key, and generating key pairs is cheap, so an attacker can generate them in bulk and keep only the ones whose resulting address happens to begin with the characters they want. Tools that do this are published openly and are used legitimately by services that want a readable prefix in their own address. The economics are simple and worth carrying in your head: an onion address is written in base32, so each character carries five bits, and every extra character you insist on matching multiplies the search by thirty-two. Matching the first handful of characters of a target address is ordinary work on ordinary hardware. Matching all fifty-six is not something anyone can do, and that gap is the whole reason step two says all the characters rather than "check that it looks right".

The practical consequence is sharper than most people expect. A shared prefix is not weak evidence that you are in the right place — it is no evidence, because the prefix is precisely the part an attacker chose to match. The characters an attacker cannot control are the ones in the middle and at the end, which is why those are the ones worth reading first.

3. A source that was correct once and is not any more

Not every wrong address started out hostile. Services rotate keys, get seized, migrate to new infrastructure, or simply go dark, and the page that once listed the address does not automatically know that anything changed. A bookmark you made yourself, a note in a password manager, a screenshot in a thread from some months ago: all of them are snapshots of a claim that was true at the moment it was taken. This is the case the "open the source fresh" habit catches. You re-read the record rather than your copy of it, because only the record can tell you the right answer has moved.

4. Tampering between the page and your clipboard

This last one surprises people, and it is the reason step four exists. A web page can attach a handler to the copy event and place something other than the visible text onto your clipboard. Separately, malware running on the machine can watch the clipboard and quietly rewrite anything shaped like a wallet address or an onion address. Both are real, both are cheap to build, and both defeat an otherwise careful visual comparison, because the string you inspected and the string you pasted are no longer the same string.

Two habits close this off. Handle addresses at a Tor Browser security level where scripts are disabled, which removes the page-side version of the trick entirely. And after pasting, read the address again in the address bar, comparing the tail and one arbitrary chunk from the middle. That takes seconds, and it is enough, because an attacker who could match those parts of your address would have had no need to touch your clipboard in the first place.

torhaven warning

Notice that three of these four require no technical skill at all. The mental image of a "hacker" breaking something is misleading here and makes people defend the wrong thing. Almost everything that goes wrong at a deposit goes wrong at the level of which page you were reading and which string ended up in the box — not at the level of cryptography failing.

Comparing fifty-six characters without losing your place

"Compare all 56 characters" is easy to write and genuinely tedious to do, and a step that feels tedious is a step people quietly stop doing after the fifth or sixth time. So it is worth making the comparison fast enough that the habit survives contact with impatience.

Start with a piece of good news about the format itself. Onion addresses are written in base32 using only the lowercase letters a through z and the digits 2 through 7. The digits 0, 1, 8 and 9 never appear anywhere in a valid address, which means the classic transcription confusions — zero against the letter O, one against a lowercase L or a capital I — simply cannot occur. If you are looking at a string with a 0 or a 1 in it, you are not looking at a mis-read address. You are looking at something that is not an onion address at all, and you can stop there.

  1. Put the two strings on adjacent lines. Paste the signed copy and the copy you are about to use one directly above the other in a plain text editor, at the same font size. Almost all of the difficulty in this comparison comes from the eye travelling between two places on a screen; removing that travel removes most of the error.
  2. Read the last eight characters first. People read left to right, attackers know that, and the front of a look-alike address is the part that was deliberately made to survive a glance. The tail is the part nobody could choose. Checking it first means a substituted address is usually caught in the first two seconds rather than the last.
  3. Then chunk the rest in groups of four. Reading fifty-six characters as fourteen small groups is dramatically more reliable than reading it as one string, for the same reason phone numbers are written in blocks. Read each group as a unit and move on; do not try to hold the whole address in your head.
  4. Let the machine do it whenever you can. A human comparison is a fallback, not the preferred method. If you have a terminal, compare the strings mechanically and let the tool answer.
A='address-from-the-signed-source.onion'
B='address-you-are-about-to-use.onion'

# either the strings are byte-identical or they are not
[ "$A" = "$B" ] && echo "identical" || echo "DIFFERENT — stop"

# or compare digests, which is easier to eyeball across two machines
printf '%s' "$A" | sha256sum
printf '%s' "$B" | sha256sum

On comparing digests instead of addresses

Hashing both strings and comparing the digests is a convenience: a digest is easier to read aloud, easier to compare across two devices, and it fails loudly on a single changed character. Compare the whole digest rather than a truncated prefix of it. Truncating is common and usually harmless, but it trades away a margin for no real gain in readability, and there is no reason to accept even a theoretical trade here when the full string is right in front of you. The relevant point is simply that the comparison is now being done by something that does not get bored on the fortieth character.

What to do when the two do not match

Nothing clever. You stop, and you do not treat the mismatch as a puzzle to solve. The instinct to work out which of the two is right, using reasoning about which one seems more official or which source felt more reliable, is precisely the instinct a substituted address is counting on. A mismatch means one of your two inputs is not what you thought it was; the only safe response is to go back to a source of record and start the routine again from step one.

Checking that an address is even well-formed

Before spending a minute on comparison, there is a cheaper test that costs seconds and rules out an entire class of mistakes: is this string a structurally valid onion address at all?

A current onion address is not an arbitrary label. It is the base32 encoding of exactly thirty-five bytes — a thirty-two-byte public key, then a two-byte checksum, then a single version byte. Thirty-five bytes is two hundred and eighty bits, and base32 packs five bits into each character, so the encoding comes out to exactly fifty-six characters with nothing left over. That is why the length is fifty-six rather than "about fifty", and why you will never see a padding = on the end of one.

The checksum is computed from the key itself, which means you can recompute it and see whether the string is self-consistent. In Python, with nothing installed beyond the standard library:

import base64, hashlib

addr = "paste-the-address-here"          # without the .onion suffix
raw  = base64.b32decode(addr.upper())    # 35 bytes if the length is right
pub, chk, ver = raw[:32], raw[32:34], raw[34:35]

want = hashlib.sha3_256(b".onion checksum" + pub + ver).digest()[:2]
print("well-formed" if chk == want and ver == b"\x03" else "MALFORMED")

Be precise about what a pass means. A passing checksum tells you the string is internally consistent: you did not drop, add or mistype a character in transcribing it, and what you are holding is at least shaped like a real address. It tells you nothing whatsoever about whose service that address belongs to. Anyone can generate a valid address in a moment, and an attacker's look-alike address passes this test exactly as cleanly as the genuine one does, because it is also a real address — just not the one you wanted.

The checksum is two bytes, so a randomly mangled string still has a small chance of passing by accident; it is a filter, not a proof. Tor Browser will also refuse to connect to a malformed address, so in practice the network catches this for you eventually. Running the check yourself simply moves the discovery earlier, to a point where nothing has been committed. Use it as a fast pre-filter that rules a mangled string out, and never as a substitute for the signature check that rules the right service in.

Reading a gpg verification, line by line

Step three of the routine, "confirm the signature and fingerprint", covers the part of the process people most often get wrong. Not because the commands are difficult, but because the output is easy to misread in a way that feels like success.

  1. Import the signing key once. gpg --import source-key.asc adds it to your keyring. This step by itself establishes nothing about who the key belongs to; it only makes the key available to check against.
  2. Confirm the fingerprint through a different channel. gpg --fingerprint source@example prints forty hexadecimal characters, conventionally shown in ten groups of four. Compare that fingerprint against a copy you obtained some other way — a different site, a printed copy, a person you already trust. This is the step that turns an anonymous key into a known one, and it is the one most often skipped.
  3. Verify the file. For a detached signature, gpg --verify addresses.txt.asc addresses.txt — signature first, then the file it covers. For a clear-signed file, where the signature is wrapped around the text itself, gpg --verify addresses.txt.asc alone is enough.
  4. Read the output carefully, not quickly. The difference between a pass and a failure is a specific word, and the surrounding lines are noisier than they need to be.
  5. Only now, read the address out of the verified file. Not out of the page that linked to it, and not out of your memory of what it said last time.

"Good signature" and the warning that follows it

A successful verification typically prints something close to this:

gpg: Signature made Mon 01 Jan 2026 12:00:00 UTC
gpg:                using EDDSA key 1111222233334444555566667777888899990000
gpg: Good signature from "Example Source <source@example>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 1111 2222 3333 4444 5555  6666 7777 8888 9999 0000

Two things are happening in that output and they answer different questions. Good signature is the cryptographic result: the file has not been altered by so much as a byte since it was signed, and it was signed by the holder of that key. That part is settled. The WARNING underneath is not a failure and does not weaken the line above it — it is gpg saying, honestly, that it has no opinion about whether that key belongs to the party named beside it. Answering that question is your job, and it is what step two above is for. Once you have checked the fingerprint out of band, you can record that fact locally with gpg --lsign-key, after which the warning stops appearing and its absence starts carrying meaning.

What an actual failure looks like

Three outputs mean stop. BAD signature means the file was changed after signing, and the address inside it is worthless regardless of how plausible it looks. Can't check signature: No public key means you do not have the signing key at all — and importing it from the same page that served you the signature closes the loop without proving anything, since a party who can serve a forged file can serve a matching forged key just as easily. And a good signature from a key whose fingerprint does not match your out-of-band copy is the most dangerous of the three, because everything reads as a pass except the one line that matters.

If you are wiring this into a script rather than reading it, gpg --verify exits with status zero on a good signature and non-zero otherwise, and --status-fd 1 adds machine-readable GOODSIG, VALIDSIG and BADSIG lines that are stable across versions in a way the human-readable text is not.

A worked example

Suppose you are about to fund a Drughub account and a signed source lists its address. You would read it from that source, compare all 56 characters, confirm the signature, and only then copy it by hand. An address of that form looks like this:

torhaven verification check

drughubdk5bmh4w6q3uubnkd3rgo2hjydjf5t6yphzmqfbrgplbs7fid.onion

Teaching example only, shown so you can see the full 56-character shape. Do not deposit against an address from a guide. Cross-check the canonical list on torindex and confirm the signature on torverify first.

After the deposit

Once a deposit clears, note the address you used somewhere you control, so next time you can spot if the signed source has changed. If it has, that is worth understanding before you send again, because a legitimate rotation and a hostile takeover can look the same at a glance. The signature is what tells them apart, which is why the check never really retires.

Recording the address without weakening the habit

A saved address is a convenience, not a shortcut around verification — that distinction matters more than it sounds. Store it in a password manager such as KeePassXC or a secure note if you like, but treat every saved copy as a starting point for the next check, not a substitute for it. This torhaven guide's whole premise is that the check costs a minute; skipping it because a save file says the address has not changed defeats the purpose of running the check in the first place.

Verifying once vs. verifying every time

A reasonable question after the first successful check: does this routine really need repeating every single time, or does verifying once establish enough trust to skip it later? The honest answer depends on what actually changed between visits, not on how much effort feels proportionate.

An address you verified yesterday and are using again today, with nothing else different, carries forward the same trust — you are not required to re-run gpg for the exact same, unchanged record on every page load. What resets that trust is any change in the picture: a new session after time away, a different device, a link that arrived through a new channel rather than your own saved copy, or simply enough time passing that a rotation would not be surprising. Any of those is a reason to re-run the check rather than assume yesterday's verification still applies.

The habit worth building is not "verify constantly" but "verify at every point of change." That covers the deposit moment this torhaven guide focuses on, but the same logic extends to any address you are about to trust with something that matters — a login, a PGP key import, a mirror you have not personally checked before.

What this routine does not protect you from

A check that gets oversold stops being useful, because a reader who believes it covers everything relaxes about the things it never touched. So here, plainly, is the boundary of what a verified address buys you.

It does not make the service honest. A perfectly verified address can belong to a market that accepts deposits for months and then stops answering. Verification answers the question "am I talking to the party I think I am talking to". It does not, and cannot, answer "is that party worth trusting with money". Those are separate problems and only the first one has a technical solution.

It does not survive a compromised machine. Every step of this routine runs on your computer — the comparison, the gpg call, the paste into the browser. Software that is already on the machine and already hostile sits underneath all of it. If the possibility of that is a real part of your threat model, an amnesic system that starts from a known state each boot is a more meaningful answer than any amount of care taken inside a compromised one.

It does not tell you the service is still under the same control. Keys live on servers, and servers get seized. When that happens, the address continues to resolve and the signature over an old list continues to verify, while somebody else answers on the other end. This is a genuine limit with no clean fix from the outside, and it is the honest reason this guide never says a verified address is a safe address.

It does not cover the payment details themselves. The signature is over the address. The amount, the memo or payment-ID field, and the specific subaddress you are shown at checkout are all outside it, and each one is a place where a substitution can be made after every check you ran has passed.

It does not extend past the page loading. Reusing a password, logging in with an identifying handle, or opening a downloaded file outside the browser will undo the protection the routine gave you, and it will do so entirely outside anything the routine ever looked at.

None of this is an argument for skipping the check. It is an argument for knowing exactly what it earns: it removes the most common and most avoidable way that money goes to the wrong place, and it leaves the rest of the risk where it actually lives — in the counterparty, in the machine, and in the habits that follow.

Mistakes that undo an otherwise correct check

Verifying the address but not the amount or memo field

A signature check confirms the address is genuine — it says nothing about a payment memo, a Monero subaddress index, or an amount field that malware or a compromised clipboard manager altered separately. Read the full payment screen after verification, not just the address line, especially on a device where clipboard-hijacking malware is a realistic risk.

Trusting a screenshot of a verified address

A screenshot posted anywhere — a forum, a chat, even a page that otherwise looks legitimate — proves nothing about whether the address in the image matches a currently signed record. Treat a screenshot exactly like an unverified claim: a starting point for your own check, never a substitute for running it.

Assuming a longer, more complex-looking address is safer

Onion v3 addresses are a fixed 56 characters by design; length and apparent complexity are constant across genuine and fake addresses alike. A convincing-looking string is not evidence of anything — the signature match is the only test that matters, regardless of how the address looks to the eye.

Common torhaven questions

Why check the address again if I have a bookmark?

Keys rotate and services get seized, so a bookmark can quietly point somewhere it no longer should. Re-checking against a signed source before a deposit costs a minute and catches exactly that case.

Is the padlock in Tor Browser enough?

No. Onion services are encrypted by default, so there is no padlock to earn and no certificate authority vouching for who is behind the address. The verified address itself is the proof, not a lock icon.

What if only the last few characters differ?

Then it is a different site. Attackers grind look-alike addresses that share a prefix precisely so a quick glance passes, which is why you compare the whole 56-character string.

The checksum in the address passes. Is that not proof enough?

No, and this is a common and expensive misunderstanding. The two checksum bytes inside an onion address prove the string is internally consistent — that nothing was dropped or mistyped in copying it. A look-alike address generated by an attacker is a genuine, correctly formed address too, so it passes the same test cleanly. Well-formed and correct are different properties, and only a signature over the address distinguishes them.

gpg says "Good signature" but also prints a warning. Did it fail?

No. "Good signature" is the cryptographic verdict: the file is unaltered and was signed by that key. The warning underneath says gpg has no independent evidence that the key belongs to the name printed beside it — which is true until you confirm the fingerprint through a second channel yourself. A real failure reads "BAD signature", or reports that no public key was available to check against.

Can I just trust that Tor Browser will not connect to a fake address?

Tor Browser connects to whatever address you give it. It has no list of legitimate services and no way to know which one you meant, because an onion address is generated by whoever runs the service, not issued by an authority that could vet it. The browser will refuse a string that is malformed, and that is the entire extent of its opinion. Everything past that is your check.

Is a verified address a safe address?

It is a correct address, which is not the same thing. Verification confirms you have reached the party whose key signed the record. Whether that party handles escrow honestly, resolves disputes, or is still run by the same people as last month are questions no address check can answer, and any guide implying otherwise is overselling it.

Why torhaven treats this routine as its own guide

torhaven could have folded this checklist into the onion-address torhaven guide as a closing paragraph. It did not, because the moment before a deposit is different enough from the moment of first learning what an address is that torhaven wanted a page a reader could bookmark and return to specifically for this step, without wading back through the fundamentals.

What torhaven assumes you already did

This torhaven guide assumes you have already read why an address is self-authenticating and why comparing all 56 characters matters — that groundwork lives in torhaven's onion-address guide, not here. What this torhaven page adds on top is the specific, repeatable routine: where to pull the address from, what a signed source looks like, and what to do when the pieces do not line up.

How torhaven's Torzon profile uses this routine

torhaven's own Torzon profile points back to this torhaven guide rather than repeating the routine inline, on the theory that a reader who has internalised the check once should not have to relearn it every time torhaven writes about a specific project. If a future torhaven profile covers a different market, expect the same pattern: the mechanics live here, the project-specific application lives there.