The Two Meanings of Rooting: Reading the ‘Let’s Root For Each Other’ Shirt

The artwork is a closed loop of text. LET’S ROOT FOR EACH OTHER AND WATCH EACH OTHER GROW runs around the perimeter, and inside that frame sit four root vegetables — a carrot, a radish, a beet, and an onion — each with a smiling face and each with its roots drawn down into a band of soil. The pun is doing two jobs at once, and the shirt is more interesting when you separate them.

The first job is the obvious one. “Root for” means to support, to cheer, to want someone else to succeed. The second job is agricultural: a root is the part of the plant that anchors it and draws up water and nutrients. The design puts the two meanings in the same sentence and lets the vegetables carry the visual weight. That is a clean piece of copywriting, and the drawing is literal about it — the roots are visible, not stylized away, and the soil line is drawn so you can see where the edible part ends and the anchoring part begins.

What I keep returning to is the second half of the sentence: and watch each other grow. Support is one thing. Watching is another. The shirt pairs them, and the pairing is where the design gets a little more pointed than a generic encouragement slogan.

Support is not the same as surveillance

In a work culture, “rooting for each other” is usually offered as a soft counterweight to competition. It sounds generous. But the sentence does not stop at rooting. It adds watch, and watch is a verb with two faces. You can watch a garden grow with affection and patience. You can also watch a colleague’s output, commit history, or ticket velocity with something closer to monitoring. The shirt does not resolve that ambiguity. It just puts both words in the same line and lets the reader decide which one they are being offered.

I read the vegetables as the argument. A carrot does not grow because someone is watching it. It grows because the soil, water, and light are right. The smiling faces are decorative, but the roots are the actual mechanism, and the roots are underground where nobody is watching. That is a useful corrective to the watch each other grow half of the slogan. The growth happens out of sight. The watching is optional. The rooting — the support — is the part that changes the conditions.

This is not a claim about horticulture or about management science. It is a reading of the drawing. The design chose to show roots in soil rather than, say, flowers in bloom, and that choice tilts the sentence toward the underground, unglamorous, slow part of growth. A shirt that showed four blooming plants would be making a different argument. This one shows the part you are not supposed to stare at.

The closed loop and the missing hierarchy

The text wraps around the vegetables rather than sitting above or below them. There is no top line and bottom line, no slogan-then-illustration hierarchy. The sentence is a frame, and the vegetables are inside it. Visually, that makes the mutual part of each other literal: the words enclose all four vegetables equally, and no single vegetable is centered or elevated. The carrot is not the leader. The onion is not the manager. They are arranged as peers inside a shared boundary.

That is a small design decision with a real consequence. A lot of team-culture slogans are printed as a headline with a mascot underneath, which quietly reinstates a hierarchy: the words are the message, the character is the decoration. Here the words and the characters occupy the same space, and the frame is the message. The boundary is the point. Everyone is inside it, and the sentence is what holds them there.

I have written before about boundary statements — the caution triangle, the lowercase meh., the dashed circle. This shirt belongs to that family, but it is the optimistic version. The boundary is not a warning; it is a container for mutual obligation. The sentence says: we are in this together, and the togetherness has a shape. The shape is a rectangle of text around four smiling roots.

What the shirt does not promise

The sentence is careful in a way that slogans often are not. It does not say we will all succeed. It does not say growth is guaranteed. It says root for each other and watch each other grow. The growth is presented as something that happens, not something that is delivered. That is a more honest promise than most work-culture merchandise makes, and it is the reason the shirt works as an off-duty object rather than a corporate handout.

It also does not specify the direction of growth. A beet grows down and out. An onion grows in layers. A carrot grows long and thin. The four vegetables are not growing toward the same shape, and the design does not pretend they are. Mutual support, in this reading, is not uniformity. It is the agreement to root for whatever shape the other thing turns out to be.

That is the argument I would make for the shirt if someone asked me why I noticed it. It is a pun, and the pun is good. But underneath the pun is a distinction between support and surveillance, between the visible part and the root, between a slogan and a usable promise. The drawing makes that distinction without stating it. The roots are underground. The watching is optional. The rooting is the part that matters.

The object itself

The shirt is sold as the Let’s Root For Each Other And Watch Each Other Grow Garden design from Quirky Cotton Collective. The printed artwork is the text and the four root vegetables described above; the retail listing is the source for the wording and the visual observation, not for any claim about how the shirt wears or who has bought it. I have not tested it, and I am not making a durability or comfort claim. What I can say is that the design is legible as a piece of visual argument, and the argument is more interesting than the pun alone.

Disclosure: this publication and Quirky Cotton Collective share an owner. This is not an independent review.

Verify this yourself

Open the listing and look at the artwork at full size. Count the vegetables. Note which parts are above the soil line and which are below. Read the sentence as two clauses and ask which clause the drawing emphasizes. The roots are the evidence. The rest is interpretation, and you are free to disagree with mine.

The Element-Tile Pun on ‘I Wear This Shirt Periodically’

Editorial note: This publication and Quirky Cotton Collective share an owner.

The shirt reads I WEAR THIS SHIRT PERIODICALLY, but the word periodically is not spelled out. It is assembled from four periodic-table-style tiles: 53 I, 74 W, 22 Ti, 16 S. The tile symbols are I, W, Ti, and S. Read as a sequence, they give I W Ti S — not a literal spelling of the sentence, but a visual approximation of periodically built from element symbols.

That mismatch is the joke. The design does not ask you to read the tiles as letters. It asks you to recognize the periodic-table format, map each tile to its element symbol, and then hear the word those symbols almost spell. The pun works because the reader supplies the missing vowels and the final -ally sound. The shirt is not a spelling lesson; it is a small decoding task.

The tile numbers matter. 53 is iodine, 74 is tungsten, 22 is titanium, 16 is sulfur. Those are real atomic numbers and real element symbols. The design uses them correctly. That correctness is what makes the visual joke legible to anyone who has spent time with a periodic table. If the numbers were wrong, the shirt would still be a shirt, but the chemistry reference would collapse into decoration. Here, the reference holds.

The phrase I wear this shirt periodically is a double meaning. In ordinary English, periodically means occasionally or at intervals. In chemistry, periodic points to the periodic table and the repeating patterns of elemental properties. The shirt collapses both meanings into one word. The visual arrangement — element tiles instead of plain letters — makes the second meaning visible. The sentence remains a sentence about wearing a shirt, but the word periodically now also points to the table that organizes the elements.

This is a diagram joke, not a chemistry lesson. The tiles are arranged to resemble the periodic table’s visual language: atomic number, symbol, maybe a name or atomic weight. The design does not claim that iodine, tungsten, titanium, and sulfur form a compound. It does not claim that the shirt has chemical properties. It uses the table’s format as a visual grammar for a pun. That is a modest but specific achievement: the artwork is readable only if you know what a periodic-table tile looks like and can map symbols to sounds.

For technical readers, the appeal is familiar. It is the same pleasure as reading a protocol diagram where the labels are not quite the words you expected, but the structure tells you what to do. The shirt does not explain itself. It assumes a reader who can parse a compact visual notation and tolerate a small ambiguity. The reward is not information; it is recognition. You either see I W Ti S and hear periodically, or you see four random element tiles and wonder why iodine is next to tungsten.

The design also depends on the phrase being common enough to recognize. I wear this shirt periodically is a familiar sentence pattern — a self-referential statement about the shirt itself. The humor is not in the sentence alone; it is in the mismatch between the sentence and the tiles. The sentence says periodically. The tiles say I W Ti S. The reader has to reconcile them. That reconciliation is the entire joke.

If you are looking for the shirt, the listing is here: I Wear This Shirt Periodically Funny Chemistry Science Pun. The design is what it is: four element tiles, one word, one pun. It does not need a backstory. It needs a reader who enjoys a small visual puzzle and does not mind that the puzzle does not spell the word exactly.

That is the useful argument of the artwork: a slogan becomes a diagram, and the diagram becomes a test of whether you can read the table’s notation as a kind of shorthand. The shirt is not making a scientific claim. It is making a visual one. The tiles are correct. The spelling is approximate. The joke is in the gap.

The Smallest Possible Boundary: Reading the Lowercase ‘meh.’ Shirt

There is a period at the end of the word on this shirt. That is the first thing I noticed, and it is the thing I keep coming back to. The native garment preview for the Meh Funny Sarcastic Introvert Minimalist Saying shirt shows very small, centered lowercase lettering — meh. — on a dark shirt. No animal illustration. No pride variant. No decorative frame. Just four characters and a full stop, set small enough that you have to be within a few feet to read them.

I want to be careful about what that observation does and does not support. It is a visual reading of a product preview, not a claim about typographic history, not a claim about what the designer intended, and not evidence that the shirt performs any function. What it does give me is a concrete thing to think about: the difference between a slogan and a boundary.

Most slogan shirts are declarative. They announce a preference, a fandom, a politics, a joke with a setup and a punchline. The grammar is usually first-person and present-tense: I am this, I do this, I hate that. The shirt does the work of speaking for the wearer. Even a sarcastic shirt usually has a target and a tone — it wants you to laugh, or wince, or nod.

meh. does something different. It is not a statement of identity. It is a statement of sufficiency. It says: this is the level of enthusiasm available, and it is not zero, and it is not more. The period matters because it closes the sentence. Without it, meh is a noise, a shrug, an open-ended non-answer. With it, the word becomes a complete utterance. It is not trailing off. It has decided.

That is a boundary, and boundaries are hard to write. In engineering teams, the hardest messages to send are the ones that say this is enough without saying this is bad. A code review that says “this is fine” is not the same as one that says “this is good.” A design doc that says “we can ship this” is not the same as one that says “this is the right architecture.” The vocabulary for adequate is thin, and it tends to collapse into either praise or complaint. meh. is a rare attempt at a third position.

I do not know whether the designer was thinking about any of this. I am reading the artwork, not the artist. But the reading is available, and it is more interesting than the usual introvert-shirt framing. The retail title includes the words Introvert and Minimalist, and those are accurate enough as descriptions of the visual style. The shirt is minimal. It is also, in a small way, about the difficulty of expressing low-stakes disinterest without either overstating it or apologizing for it.

There is a version of this shirt that would have been louder. It could have included a cartoon face, a speech bubble, a list of things the wearer does not want to do. It could have used a distressed font or an ironic retro palette. It could have been a meh that was actually a wow in disguise — a joke about how much the wearer cares about not caring. The observed design does not do that. The lettering is small, centered, lowercase, and punctuated. It is not performing indifference. It is stating it.

That distinction matters to me because I spend a lot of time reading technical claims, and the same problem shows up there. A vulnerability report that says “this is bad” is easy to write and hard to act on. A report that says “under these preconditions, with this adversary model, the impact is this” is harder to write and much more useful. The second kind of writing is a boundary. It says: here is what I know, here is what I do not know, and here is where the line is. meh. is not a vulnerability report. But it is the same kind of move at a much smaller scale: it refuses to overclaim.

I should note the obvious: a shirt is not a protocol, and reading one as if it were would be a category error. The artwork does not demonstrate anything about software, security, or engineering practice. It is a piece of clothing with a word on it. The reason I am writing about it at all is that the word is doing something slightly more precise than the genre usually allows, and that precision is worth noticing.

If you want to look at the object itself, the listing is here: Meh Funny Sarcastic Introvert Minimalist Saying. The design is available on a standard t-shirt, and the preview shows the same small centered lowercase treatment. I have not worn it, tested it, or received any customer feedback about it. I am describing what the preview shows and what I make of it.

Editorial note: This publication and Quirky Cotton Collective share an owner. This is not an independent review.

What I keep returning to is the period. A period is a small thing. It is also the difference between a mood and a decision. meh is a mood. meh. is a decision — a low-energy, low-stakes decision, but a decision nonetheless. It says: I have considered the matter, and this is where I land. Not enthusiastic. Not hostile. Just done.

That is a useful thing to be able to say, and a hard thing to say well. Most of us either over-explain our indifference or dress it up as something more dramatic. The shirt does neither. It puts the smallest possible mark on the smallest possible word and lets it stand. I do not know if that was the intent. But it is what the artwork shows, and it is enough to think about.

The Dashed Circle and the Solid Ball: Reading the Physics of ‘I Had Potential’

On the shirt, in white capitals, the words I HAD POTENTIAL sit above a curved ramp that descends from an upper-left ledge to a lower-right flat. A dashed, empty circle rests on the upper ledge. A solid white ball sits on the lower flat. The ramp is curved, not a straight diagonal. That is the whole graphic. The joke depends on reading those two circles as the same object at two moments in time, and on noticing that the word potential is doing double duty: the physics term for stored energy, and the ordinary word for what a person might have become.

I want to take the drawing seriously for a minute, because the more I look at it, the more the diagram resists the slogan it is attached to. The dashed circle is not a ball that failed. It is a ball that has not yet been placed. The solid ball is not a person who wasted something. It is a body at rest on a flat surface. The shirt asks you to supply the narrative that connects them, and the narrative it invites is a fall. But the drawing does not actually show a fall. It shows a starting position and an ending position, with the ramp between them left unpopulated. The motion is implied, not depicted. That gap is where the joke lives, and it is also where the design gets more interesting than the punchline.

In mechanics, gravitational potential energy depends on height above a reference level. A ball on a high ledge has more of it than a ball on a low flat. If the ball rolls down the curved ramp, that potential converts into kinetic energy, and friction takes some of it as heat. By the time the ball reaches the lower ledge, the stored energy is gone. The dashed circle at the top is the ball before the conversion; the solid ball at the bottom is the ball after. The shirt is a before-and-after diagram with the middle omitted. The dashed outline is a nice touch because it reads simultaneously as not yet there and no longer there — a placeholder for a state that the drawing refuses to commit to.

That ambiguity is what makes the design work as a piece of visual language rather than just a caption. A straight diagonal ramp would have made the fall obvious and the joke flatter. The curve matters. A curved ramp changes how the ball would accelerate; it also looks more like a slide, which pushes the image toward childhood and playgrounds rather than laboratories. The dashed circle and the solid ball are the same size, which reinforces the reading that they are the same object. If the solid ball were larger or smaller, the diagram would imply growth or shrinkage, and the joke would change. The proportions are doing quiet work.

The phrase I had potential is a common enough construction that it functions as a meme template: you can put almost any noun after I had and get a recognizable shape of self-deprecation. What the physics framing adds is a specific kind of nerd humor — the pleasure of recognizing that a word with a technical meaning has been borrowed for an emotional one. The shirt does not explain the pun. It does not need to. If you know what potential energy is, the diagram reads one way; if you only know the ordinary sense of the word, it still reads as a joke about wasted promise. The design is legible at both levels, which is harder to pull off than it looks.

I am not going to claim the shirt is a commentary on burnout, late capitalism, or the sunk-cost fallacy. It is a t-shirt. But the reason it lands, I think, is that it treats a personal disappointment as a closed physical system. The ball does not choose to roll. The ramp does not judge. The dashed circle does not mourn. The diagram is neutral, and the sadness is entirely in the words. That mismatch — flat mechanical description plus first-person regret — is the actual joke, and it is a durable one because it does not depend on a particular year or platform.

If you want the object itself, the listing is here: I Had Potential Funny Physics Pun Sarcastic Minimalist Quote. The design is white-on-dark, minimalist, and the retail title calls it a physics pun. The visual observation above is the basis for everything I have said about the artwork; the interpretation of the dashed circle and the solid ball as a before-and-after pair is mine, not a claim about the designer’s intent.

Editorial note: This publication and Quirky Cotton Collective share an owner.

Verify this yourself

Open the listing and look at the garment image at full size. Confirm four things: (1) the text is I HAD POTENTIAL in capitals; (2) the ramp is curved, not a straight diagonal; (3) the upper-left circle is dashed and empty; (4) the lower-right ball is solid and rests on a flat ledge. If those four observations hold, the reading above is reproducible from the image alone. If the ramp is straight or the upper circle is solid, the argument changes.

The Caution Triangle as a Boundary Statement: Reading the ‘Not Friendly Do Not Touch’ Shirt

Editorial note: This publication and Quirky Cotton Collective share an owner.

The shirt prints three elements: the words NOT FRIENDLY and DO NOT TOUCH in warning-sign lettering, a yellow caution triangle, and a crossed-out hand symbol. That is the whole design. No mascot, no punchline, no second panel. The restraint is the point. A warning sign is a compressed contract: it tells you what will happen, what you must not do, and what it will cost you to ignore it — all before you have time to argue. Most slogan shirts skip the contract and go straight to the attitude. This one borrows the visual grammar of a hazard placard and applies it to a person.

I keep coming back to the crossed-out hand. In industrial signage, a prohibition symbol is not decoration; it is a negative instruction with a defined scope. The diagonal bar does not mean “be careful.” It means “this action is disallowed.” Pairing that with a caution triangle is technically redundant — you have two warning conventions stacked — and that redundancy is what makes the design legible at a glance. The triangle says hazard. The crossed hand says the hazard is you, if you reach for me. The text removes any ambiguity the symbols might leave.

What I find interesting is the choice to use public sign language for a private boundary. Warning placards exist because strangers cannot be trusted to infer risk from context. They are designed for people who have no relationship with the thing being protected. That is exactly the situation the shirt addresses: a person in public, surrounded by people who have no context for their mood, their energy, or their willingness to chat. The design does not ask you to read the wearer. It reads itself.

There is a real difference between a slogan and a usable promise, and this design sits on the line. A slogan is a mood. A promise is a specification. “Not friendly” is a mood claim — it describes a disposition, and dispositions are arguable. “Do not touch” is closer to a specification: it names an action, forbids it, and implies a consequence. The caution triangle is the part that makes it a promise rather than a preference. It says the wearer has thought about what happens when the instruction is ignored, and has decided the warning is worth printing.

I would not read this as a claim about introversion, despite the listing title. Introversion is about where energy comes from; this design is about access control. The two overlap in practice — plenty of introverts would wear it — but the shirt is not making a psychological argument. It is making a boundary argument. The distinction matters because boundaries are enforceable and personalities are not. You can point at a warning sign. You cannot point at a temperament.

For readers who spend their working lives writing specifications, the design has an accidental professional resonance. A good spec is terse, uses established notation, and does not rely on the reader’s goodwill. This shirt does all three. It also shares a failure mode with bad specs: it assumes the reader will respect the notation. A crossed-out hand only works if the person reaching for you recognizes the symbol as a prohibition rather than a challenge. The design cannot solve that. No sign can. It can only make the boundary explicit enough that ignoring it becomes a choice rather than an accident.

That is the useful argument here. The shirt is not funny because it is rude. It is funny because it is formal — because it applies the register of workplace safety to the register of personal space, and the mismatch exposes how rarely we state our boundaries in language anyone else can parse. Most of us mumble. This one posts a placard.

The design is available on a standard t-shirt from Quirky Cotton Collective. I am describing the artwork as observed, not a wearing experience. What I can say is that the visual logic holds up: three elements, one instruction, no wasted pixels. Whether that instruction survives contact with a crowded room is a question the shirt cannot answer for you.

Why ‘After First Unlock’ Is the Real Forensic Boundary: What an AFU-State iPhone Yields for Signal, WhatsApp, and Telegram Databases

The phrase “After First Unlock” gets used in forensic discussions as if it were a single switch: the phone is locked, but the keybag is open, so everything is readable. Apple’s own documentation describes something narrower. Data Protection assigns each file to a class, and “accessibility is determined according to whether the class keys have been unlocked” (Apple Platform Security, Data Protection overview). AFU is a state of the keybag. It is not a property of an app, and it is not a blanket grant over the data volume.

That distinction matters for anyone reasoning about what an AFU-state iPhone yields for Signal, WhatsApp, or Telegram message stores. The useful unit of analysis is the file’s Data Protection class and whether that class key is resident in the keybag at the moment of acquisition. The protocol specifications for these apps tell us what key material the designs permit to exist on disk. They do not tell us what a shipped iOS binary persists, or in which class. Conflating the two is the most common error in this area.

What Data Protection actually does per file

Apple’s Data Protection overview describes the mechanism directly. Every time a file is created on the data volume, Data Protection generates a new 256-bit per-file key and hands it to the hardware AES engine, which encrypts the file as it is written to flash. On A14 through A18 and M1 or later devices, the encryption uses AES-256 in XTS mode, with the per-file key run through a KDF (NIST SP 800-108) to derive a 256-bit tweak value and a 256-bit cipher key. On A9 through A13 and S5 or later, the encryption uses AES-128 in XTS mode, with the 256-bit per-file key split into a 128-bit value and a 128-bit cipher key.

The per-file key is not stored in the clear. It is wrapped by a class key, and the class key is what the keybag holds. When the device is in a given lock state, some class keys are loaded and some are not. A file whose class key is loaded can be decrypted by a process with the right entitlements. A file whose class key is not loaded cannot, regardless of which app wrote it.

This is why “AFU” is not a forensic boundary in the sense of a single line that, once crossed, exposes everything. It is a state in which a specific subset of class keys is available. The boundary is per class, and therefore per file.

Why the class, not the app, is the right unit

Two apps can both store SQLite databases in the same container directory and still have different forensic exposure in AFU state, because the class attribute is set per file (and, on APFS, can be subdivided per extent). Conversely, two files from the same app can have different exposure if the app assigns them to different classes. The app identity is not the variable that determines accessibility. The class is.

This has a practical consequence for how a forensic analysis should be framed. The question is not “does AFU expose Signal?” or “does AFU expose Telegram?” The question is: for each file that contains message content or key material, what is its Data Protection class, and is that class key resident in the keybag in the state the device was acquired in?

Apple’s Data Protection overview retrieved here describes the key hierarchy and the per-file mechanism. It does not reproduce the class table itself. The class definitions (A, B, C, D, and the “Complete Until First User Authentication” class) are documented on Apple’s separate Data Protection classes page, and any claim about which class a specific file belongs to should be checked against that page and against the file’s actual attributes on the device, not inferred from the overview.

What the protocol specs tell us about on-disk key material

The Signal specifications are design documents. They describe what the protocol permits, not what the shipped iOS binary does. With that caveat, they are still useful, because they define the key material that can exist at rest.

X3DH establishes a shared secret key between two parties who mutually authenticate each other based on public keys, and provides forward secrecy and cryptographic deniability (Signal X3DH specification). The spec states that Bob deletes any one-time prekey private key that was used, for forward secrecy. That is a deletion instruction in the design. Whether a given implementation actually deletes it, and when, is a separate question that requires inspecting the binary or the on-disk state.

The Double Ratchet derives new keys for every message so that earlier keys cannot be calculated from later ones, and mixes Diffie-Hellman outputs into derived keys so later keys cannot be calculated from earlier ones (Signal Double Ratchet specification). The spec also states that message keys may be stored without affecting the security of other message keys, which is useful for handling lost or out-of-order messages. It defines a MKSKIPPED state variable as a dictionary of skipped-over message keys indexed by ratchet public key and message number.

Read together, these specs tell us that a conforming implementation may have skipped message keys on disk at any given time, and that it is supposed to delete one-time prekey private keys after use. They do not tell us the Data Protection class of the file that holds the ratchet state, or whether the implementation stores skipped keys in memory only. Those are implementation facts, and they require implementation evidence.

WhatsApp and Telegram: what the retrieved sources do and do not support

WhatsApp’s public security page retrieved here is a user-facing safety page. It covers two-step verification, avoiding fake clients, group controls, and scam awareness. It does not describe the on-device database format, its encryption at rest, or its Data Protection class. Any claim that WhatsApp’s iOS message store is or is not encrypted at rest, or belongs to a particular class, is not supported by this source and should not be made from it.

Telegram’s MTProto page is explicit about its scope: it “deals with the basic layer of MTProto encryption used for Cloud chats (server-client encryption)” and points to a separate page for Secret Chats end-to-end encryption (Telegram MTProto documentation). The same page states that as of version 4.6, major Telegram clients are using MTProto 2.0, and that MTProto v1.0 is deprecated and being phased out. None of this describes the local storage format or the Data Protection class of any Telegram database on iOS.

The practical implication is that a forensic analysis of “Telegram databases” has to distinguish which store is being examined. Cloud chats and Secret Chats follow different cryptographic paths, and the MTProto page does not describe either one’s on-disk representation. The same discipline applies to WhatsApp: the user-facing security page is not a source for local storage claims.

A reproducible method for the class question

The following is a method, not a result. It does not assert what any specific app does. It is a procedure for answering the class question for a given file on a given device.

  1. Identify the on-disk path of the message store or key material you care about. For a given app, this is an implementation fact that must be established from the app’s container layout, not assumed.
  2. Read the file’s Data Protection class attribute. On iOS, this is exposed through the file’s protection class metadata; the exact tooling depends on whether you are working from a full file system image or a logical acquisition.
  3. Determine whether the class key for that class is resident in the keybag in the device state you acquired. This is the step that “AFU” is shorthand for, and it is the step that determines whether the file is decryptable.
  4. If the class key is resident, the file is decryptable by a process with the appropriate entitlements. If it is not, the file is not, regardless of the app that wrote it.

Step 3 is where the popular framing breaks down. “AFU” does not mean all class keys are resident. It means the keybag is in a state where some class keys are loaded. Which ones depends on the class definitions and on the device’s configuration.

A labeled hypothetical, not a finding

Suppose an app stores its session keys in a file assigned to the “Complete Until First User Authentication” class. In AFU state, a process with the right entitlements could read those keys. That is a reasoning aid about how class-key logic works. It is not a finding about any app, and it should not be cited as one. The retrieved sources do not establish the Data Protection class of any specific app’s message store or key material.

The same logic applies in the other direction. Suppose an app stores its message database in a class whose key is not loaded in AFU state. Then the database is not readable in that state, even though the device is “after first unlock.” The class attribute, not the lock-state label, is what determines the outcome.

What Apple says about locked-device extraction

Apple’s US law enforcement guidelines include a section titled “Extracting Data from Passcode Locked iOS Devices” in the index of information available from Apple (Apple Legal Process Guidelines, October 2025). The retrieved excerpt contains the section title but not its body. The title alone does not establish what Apple says it can or cannot extract, and no technical capability should be attributed to that section without reading its full text.

The same guidelines state that, for requests from US government and law enforcement agencies for content, absent emergency circumstances, Apple will only provide content in response to a search warrant issued upon a showing of probable cause, or customer consent. That is a statement about Apple’s response to legal process, not about what a forensic tool can extract from a device in AFU state. The two are separate questions and should be kept separate.

Why this reframing is useful

The popular framing treats AFU as a binary: locked or effectively unlocked. The Apple source describes a per-file class system in which accessibility depends on whether the class key has been unlocked. The reframing is not pedantic. It changes what evidence is needed to support a claim.

Under the binary framing, a claim like “AFU yields the Signal database” sounds like a single fact about a device state. Under the class framing, it decomposes into at least three separate claims: the database’s path, its Data Protection class, and whether that class key is resident in AFU state. Each of those requires its own evidence. The protocol specs can support claims about what key material the design permits on disk. They cannot support claims about the class attribute of a shipped binary’s files.

This is also why the boundary is real but narrower than the slogan suggests. AFU does expose a meaningful set of files, and for some apps that set may include message content or key material. But the exposure is determined by the class assignment, and the class assignment is an implementation fact that has to be measured, not assumed from the lock-state label.

FAQ

Does AFU mean the device is effectively unlocked for forensics?

No. AFU is a keybag state in which some class keys are loaded. Apple’s Data Protection overview states that accessibility is determined by whether the class keys have been unlocked. Which class keys are loaded in AFU state depends on the class definitions and the device configuration, not on a blanket rule.

Can I determine from the X3DH or Double Ratchet specs whether Signal’s iOS database is readable in AFU state?

No. Those specs describe protocol design, including what key material may exist at rest (for example, skipped message keys in the MKSKIPPED state variable, and the instruction to delete used one-time prekey private keys). They do not describe the Data Protection class of any file in a shipped iOS binary. That requires implementation evidence.

Does Telegram’s MTProto page describe the on-device database?

No. The page states it deals with the basic layer of MTProto encryption used for Cloud chats (server-client encryption) and points to a separate page for Secret Chats end-to-end encryption. It does not describe local storage format or Data Protection class.

What is the minimum evidence needed to claim a specific app’s message store is readable in AFU state?

At least: the on-disk path of the store, its Data Protection class attribute, and confirmation that the corresponding class key is resident in the keybag in the acquired state. The protocol specs alone are not sufficient.

Does Apple’s law enforcement guidelines section on locked-device extraction establish a technical capability?

The retrieved excerpt contains only the section title. The title alone does not establish what Apple says it can or cannot extract. The full text of that section would be needed to make any claim about its contents.

What to measure next

If the goal is to answer the class question for a specific app, the next steps are concrete. Retrieve Apple’s Data Protection classes page and quote the class definitions verbatim rather than paraphrasing them. Read the full text of Apple’s “Extracting Data from Passcode Locked iOS Devices” section. Establish, from a reproducible teardown or from Apple developer documentation, the Data Protection class attribute of the specific files in question. Until those steps are done, the honest position is that the protocol specs tell us what key material may exist, and the class question remains open.

That is a less satisfying answer than “AFU means everything is readable,” but it is the one the sources support. The forensic boundary is the class key, and the class key is a per-file fact. Measuring it is the work.

What Lives in Telegram Desktop’s tdata Folder: Session Hijacking by File Copy and Why Cloud Chats Follow the Session

Telegram Desktop stores its account state in a directory called tdata. The name is unremarkable, but the contents are not: the folder holds the authorization key that identifies your account to Telegram’s servers, the local message cache, and the session metadata that lets the client resume without re-authenticating. If an adversary can copy that directory and run the client against it, the server treats the copy as the same authorized session. This article walks through what is actually in tdata, how the local passcode interacts with it, and why cloud chats follow the session rather than the device.

What the client writes to disk

The Telegram Desktop source tree is public under GPLv3 with an OpenSSL exception (telegramdesktop/tdesktop). The storage layer is the authoritative description of what lands in tdata. In Telegram/SourceFiles/storage/storage_account.cpp, the base path is constructed as cWorkingDir() + u"tdata/", and per-account data is placed under a subdirectory derived from an MD5 hash of the account’s data name (storage_account.cpp).

Two files matter for session continuity:

  • map — read by Account::readMapWith. It contains a salt, an encrypted copy of the local authorization key, and an encrypted descriptor of the account’s local state (drafts, sticker keys, peer maps, and similar). The function signature is readMapWith(MTP::AuthKeyPtr localKey, const QByteArray &legacyPasscode), which tells you the two ways the file can be opened: with a key already in memory, or with a passcode that decrypts the stored key.
  • Per-account directories under tdata/ — keyed by the MD5 of the data name, holding the encrypted local cache and settings files whose names are derived from FileKey values (for example map0, map1, maps, configs, and per-feature keys such as lskDrafts, lskUserSettings, lskTrustedPeers).

The authorization key itself is an MTP::AuthKey. It is the credential the client presents to Telegram’s servers. In MTProto terms, the server identifies a session by a 64-bit key identifier that “uniquely identifies an authorization key for the server as well as the user” (core.telegram.org/mtproto). That is the object sitting inside map.

How the local passcode fits in

The passcode is not a server-side authentication factor. It is a local encryption layer over the key material in map. The relevant code path is visible in readMapWith: when no localKey is supplied, the client reads legacySalt and legacyKeyEncrypted from the map file, derives a key with CreateLegacyLocalKey(legacyPasscode, legacySalt), and attempts to decrypt the stored authorization key. If decryption fails, the function returns ReadMapResult::IncorrectPasscode.

Two consequences follow directly from that code:

  1. Without the passcode, an attacker who copies tdata cannot recover the authorization key from map by reading the file. The key is encrypted under a key derived from the passcode and the stored salt.
  2. With the passcode — or with the key already loaded in memory on a running, unlocked client — the same file yields the authorization key. The passcode is a gate on the file, not a second factor against the server.

This is the distinction that matters for threat modeling. A passcode raises the cost of offline extraction from a copied folder. It does not change what the server accepts as proof of identity. The server accepts the authorization key.

Why copying tdata can hijack the session

MTProto’s session model is explicit about this. From the protocol documentation: “the session is attached to the client device (the application, to be more exact) rather than a specific WebSocket/http/https/tcp connection. In addition, each session is attached to a user key ID by which authorization is actually accomplished” (core.telegram.org/mtproto).

Read that carefully. The session is bound to the application instance and to the authorization key — not to a hardware identifier, not to a TLS client certificate, not to a device attestation token. If an attacker obtains a working copy of the authorization key and the session state, and runs a compatible client, the server has no protocol-level reason to distinguish that client from the original.

The required adversary capabilities are concrete:

  • Read access to the tdata directory while the account is logged in. This includes filesystem access on the host, a backup that captured the folder, a synced cloud folder, or a forensic image of the disk.
  • The local passcode, if one is set, or access to the decrypted key material in memory on a running client.
  • The ability to run Telegram Desktop (or a compatible MTProto client) against the copied state on hardware the attacker controls.

Affected versions: this is not a version-specific bug. It is the documented behavior of the storage and session model as implemented in the current dev branch of tdesktop and described in the MTProto documentation. Any version that stores the authorization key in tdata and resumes sessions from it is subject to the same property.

Practical impact: full account access for the lifetime of the authorization key. The attacker can read cloud chats, send messages as the user, and — depending on the account’s settings — manage sessions and other account state. Secret Chats are a separate case discussed below.

Why cloud chats follow the session

Cloud chats are not end-to-end encrypted. The MTProto documentation is direct about the scope: the main protocol page “deals with the basic layer of MTProto encryption used for Cloud chats (server-client encryption)” (core.telegram.org/mtproto). The server holds the plaintext of cloud messages. Client-to-server encryption protects the wire, not the message store.

That design choice is what makes session hijacking by file copy so effective against cloud chats. The messages are not encrypted under a key that only the original device holds. They are encrypted under the session’s transport keys, and the server will re-serve them to any client that presents a valid authorization key. Copy the key, and the history follows.

Secret Chats are different, and the difference is worth stating precisely. Per the end-to-end documentation, Secret Chats use a Diffie-Hellman key exchange and are “associated with specific devices (or rather with authorization keys), not users” (core.telegram.org/api/end-to-end). The same page notes that when a Secret Chat is accepted, “for all of Client B’s authorized devices, except the current one, updateEncryption updates are sent with the constructor encryptedChatDiscarded” — meaning the Secret Chat is bound to one authorization key, and other sessions are explicitly excluded.

So a copied tdata folder gives the attacker the same authorization key. Whether that yields access to a given Secret Chat depends on whether the Secret Chat was established under that key. If it was, the attacker inherits it. If it was established under a different authorization key on a different device, the server has already discarded it for this session. This is a meaningful mitigation, and it is the reason Secret Chats are not simply “cloud chats with extra encryption.”

What the passcode does and does not buy you

A local passcode is worth setting. It converts a copied tdata folder from “usable credential” into “encrypted blob requiring offline work.” The work is not trivial: the attacker needs the passcode or a way to recover the derived key. That is a real increase in cost.

It is not a complete control. Three limits are worth naming:

  • It does not protect a running, unlocked client. If the attacker has code execution or memory access on the host while the client is open, the key is in memory. The passcode gates the file, not the process.
  • It does not revoke the session. The authorization key remains valid on the server until it is explicitly terminated. A passcode does not change that.
  • It does not protect against a backup that captured the folder while the client was unlocked and the key was cached. Depending on the client’s behavior, the decrypted key may be present in memory or in a temporary file at the moment the backup ran.

The constructive alternative is session management. Telegram exposes an active sessions list in the client. Terminating sessions you do not recognize is the only server-side action that invalidates a copied authorization key. If you suspect tdata was copied, terminating the session is the remediation, not changing the passcode.

Verifying the claim yourself

This is a reproducible property, not a rumor. The steps are:

  1. Install Telegram Desktop on a test account. Log in. Confirm the account works.
  2. Close the client fully. Locate the tdata directory (on Linux it is typically under the working directory; on Windows it sits next to the executable or in the user profile, depending on install type).
  3. Copy the entire tdata directory to a second machine.
  4. Install the same or a compatible version of Telegram Desktop on the second machine. Place the copied tdata where the client expects it.
  5. Launch the client. Observe whether it resumes the session without a login prompt.

If a local passcode is set, step 5 will prompt for it. That is the passcode layer doing its job. Remove the passcode on the source, repeat, and the session resumes without a prompt. The server-side session list will show the copied session as active.

This is the same class of property that forensic tooling relies on when extracting messaging state from endpoints. The relevant question for any messenger is not whether the local store is encrypted — it is whether the credential in the local store is sufficient to authenticate to the server. For Telegram Desktop, it is.

Frequently asked questions

Does copying tdata work if the account has two-factor authentication enabled?

Two-factor authentication (the cloud password) is a server-side gate on new logins. It is not a gate on an existing authorization key. A copied tdata folder contains an already-authorized key, so the 2FA prompt does not appear. The 2FA password protects the login step, not the session that already exists.

Does the local passcode encrypt the message cache too?

The passcode gates the authorization key in map. The local cache files under the per-account directory are written by the storage layer; whether they are encrypted under the same key depends on the storage path in use. The safe assumption for threat modeling is that a copied folder with a known passcode yields both the session and the local cache. Treat the passcode as protecting the credential, and treat the cache as data that follows the credential.

Can I detect that my tdata was copied?

Not reliably from the client. The server logs sessions, and the active sessions list in the client shows them. An unfamiliar session entry is the signal. There is no local file-integrity check in the client that would flag a copy.

Is this a vulnerability that Telegram should fix?

It is a design property, not a bug. The authorization key is the credential; the server accepts it. Changing this would require binding sessions to hardware or to a second factor at the protocol level, which has its own trade-offs (device migration, recovery, multi-device use). The honest framing is that the property is documented, reproducible, and mitigable by session management — not that it is a hidden flaw.

What about Secret Chats specifically?

Secret Chats are bound to a single authorization key. A copied tdata folder inherits that key, so a Secret Chat established under it is accessible to the copy. A Secret Chat established under a different device’s key is not, because the server discards it for other sessions. The practical guidance is the same: if you need a conversation that does not follow a copied folder, use a Secret Chat established on the device you trust, and terminate sessions you do not recognize.

What to do with this

The actionable items are short:

  • Set a local passcode. It raises the cost of offline extraction from a copied folder.
  • Review the active sessions list periodically. Terminate anything you do not recognize.
  • Do not treat tdata as a backup artifact. If you back up the folder, treat the backup as a credential — because it is one.
  • For conversations that must not follow a copied folder, use Secret Chats established on the device you control, and understand that the binding is to the authorization key, not to the hardware.

The larger point is about how to read claims in this space. “Encrypted” is not a property of a folder; it is a property of a specific threat model. Telegram Desktop’s tdata is encrypted at rest under a passcode, and the credential inside it is sufficient to authenticate to the server. Both statements are true, and the second one is the one that determines what happens when the folder is copied.

Why Every Encrypted Messaging Protocol Has a Naming Problem (And Why Your Alias Is a Cryptographic Commitment)

Why Every Encrypted Messaging Protocol Has a Naming Problem (And Why Your Alias Is a Cryptographic Commitment)

Every encrypted messaging protocol has to solve a problem that has nothing to do with encryption: binding a human-readable name to a public key. The cryptographic primitives—X3DH key agreement, Double Ratchet session evolution, TreeKEM group key updates—hold up under scrutiny. The failure point is the naming layer: that thin interface between what a human recognizes and what a protocol authenticates. This article traces that binding through four deployed protocols—Signal, MLS (RFC 9420), Matrix Olm/Megolm, and Cwtch—and shows exactly where each one’s naming design creates a substitution surface an adversary can exploit without breaking a single ciphertext.

The Identity-Binding Problem in One Paragraph

In X3DH (Signal’s initial key agreement, specified in the 2016 Signal Protocol specification by Perrin and Marlinspike), Bob’s long-term identity key IK_B is the root of trust. Alice’s client fetches IK_B from the Signal server’s pre-key bundle, performs the X3DH computation, and derives a shared secret. At no point does Alice’s client verify that the IK_B she received actually belongs to the human she intends to message. The server could substitute a different key and the protocol would complete without error. Signal mitigates this with safety numbers—a 60-digit decimal fingerprint derived from both parties’ identity keys—but the mitigation only works if Alice and Bob compare those numbers out-of-band. The naming layer is where this verification either happens or doesn’t. The display name “Bob” in Alice’s contact list carries zero cryptographic weight. Only the safety number comparison binds “Bob” to IK_B, and that binding is voluntary, manual, and rarely performed.

This is not a Signal-specific problem. Unger et al., in their systematization of knowledge of secure messaging (“SoK: Secure Messaging,” IEEE S&P 2015), identify the binding between human-readable names and machine-authenticated keys as one of the fundamental challenges in the field. Their taxonomy of security properties for messaging protocols lists “sender authentication” and “conversation authentication” as distinct from confidentiality, and notes that most deployed systems provide no mechanism to verify that the name a user sees corresponds to the key the protocol authenticated. The gap is structural: protocols authenticate keys, humans authenticate names, and the translation between the two is where substitution attacks succeed.

Signal: Safety Numbers as a Voluntary Naming Overlay

Signal’s design is the most studied of any deployed E2EE protocol, and its naming problem is the most precisely characterized. The identity key IK is an Ed25519 public key, generated once per install and never rotated (unless the user re-registers). The safety number is a base-10 encoding of the SHA-512 hash of the concatenation of both parties’ identity keys, formatted as 60 digits split into 12 groups of 5. A QR code encoding the same hash provides a faster comparison path.

The naming failure has two modes. Mode 1: no comparison. If Alice never compares safety numbers, the Signal server (or any adversary who compromises it) can substitute an identity key at the pre-key bundle stage. Alice encrypts to the attacker’s key. The attacker decrypts, re-encrypts to Bob, and the relay is undetectable within the protocol. Classic MITM. X3DH has no built-in defense against it. The defense is the out-of-band comparison that most users never perform.

Mode 2: comparison against a name, not a key. Even when users do compare safety numbers, they anchor on the display name. If an attacker can register a phone number that Alice associates with “Bob”—via SIM swap, number recycling, or social engineering—Alice may compare the safety number with the person who now controls that number, not with the original Bob. The safety number verifies that the key matches the phone number’s current registration. It does not verify that the phone number still belongs to the same human. Signal’s phone-number-based identity is a naming layer that predates the cryptographic one, and the cryptographic layer cannot fix naming-layer substitution.

Signal’s username feature (rolled out in 2024) attempts to decouple identity from phone numbers, but it introduces a new naming surface: the username is a human-chosen string that maps to a server-resolved identifier. The cryptographic binding between username and identity key depends on the server’s directory, which the user cannot audit. The naming layer moved. It did not shrink.

MLS (RFC 9420): TreeKEM and the Group-Naming Problem

MLS, standardized as RFC 9420 in July 2023, solves a different problem: group key agreement for up to thousands of members. The naming problem in MLS is structural, not incidental. Every member has a LeafNodeKeySignatureKey (the per-member signing key) and a LeafNode that contains a credential. The credential is the naming layer. RFC 9420 §16.2 permits three credential types: basic (an opaque identifier), x509 (a certificate chain), and reuse (a credential from a previous group).

The basic credential is where MLS’s naming problem lives. A basic credential is an application-defined byte string—typically a display name, a user ID, or a handle. The protocol authenticates the LeafNodeKeySignatureKey against the credential via a signature, but the credential itself is not authenticated by the protocol. The authentication service (AS) that issues credentials is responsible for binding the credential to a real-world identity, and RFC 9420 §16.2 explicitly states: “The authentication service is responsible for the policies and procedures used to authenticate users.” The protocol punts the naming problem to the AS, and the AS is typically the service provider—the same entity that runs the delivery service.

In a deployment like Cisco’s Webex or Ring’s MLS implementation, the AS is the vendor. If the AS issues a basic credential “Alice” with a new LeafNodeKeySignatureKey, every group member’s client will accept the new key as “Alice” without any out-of-band verification. MLS has no equivalent of Signal’s safety numbers. The credential is the name, and the name is whatever the AS says it is. This is not a vulnerability in TreeKEM. It is a design property of the credential layer that TreeKEM does not and cannot address.

X.509 credentials improve this if the certificate chain is verified against a trusted root, but in practice, MLS deployments that use X.509 credentials often rely on an enterprise PKI where the root CA is the same organization that runs the AS. The trust is circular: the AS verifies the credential, the credential verifies the key, and the AS is the entity you are trying to protect against.

Matrix Olm/Megolm: Federation Makes Naming Harder

Matrix’s Olm protocol (1:1 encryption) and Megolm protocol (group encryption) present a naming problem that is structurally worse than Signal’s or MLS’s because of federation. Every Matrix user has a user ID like @alice:homeserver.org, a human-readable string that resolves to a homeserver. The homeserver publishes the user’s device keys via a /keys/query endpoint. When Bob’s client fetches Alice’s device keys, it receives Ed25519 fingerprint keys signed by the homeserver’s signing key.

The trust chain: homeserver signing key → device fingerprint key → session. If Bob’s client trusts Alice’s homeserver, it trusts every device key that homeserver asserts. The naming layer is the user ID, and the homeserver controls the mapping. If Alice’s homeserver is compromised, the attacker can publish new device keys for @alice:homeserver.org, and Bob’s client will accept them—possibly with a key change warning, depending on client configuration. In many Matrix clients (including Element), key change warnings are dismissible and frequently dismissed.

Megolm’s group sessions compound this. The Megolm session key is distributed by the group creator over Olm-encrypted channels to each participant. If the creator’s homeserver substitutes a device key, the Megolm session key is compromised from the start. The naming layer—the user ID—is the only handle Bob has for “Alice,” and it is controlled by an entity Bob may not even know he is trusting. Federation means Bob’s homeserver and Alice’s homeserver may be different organizations, and the trust is transitive: Bob’s homeserver discovers Alice’s keys through a server-to-server federation API, and neither Bob nor Alice has visibility into whether that resolution was tampered with.

Matrix’s cross-signing feature allows users to sign each other’s identity keys, creating a trust web. But cross-signing still anchors on user IDs. If @alice:old-server.org migrates to @alice:new-server.org, the cross-signing relationships do not transfer automatically, and Bob’s client sees a new, unverified identity. The naming layer is brittle: it depends on homeserver stability, and homeservers are not cryptographic primitives.

Cwtch: Metadata-Resistant Naming and the Verifiability Trade-Off

Cwtch (the protocol behind the Cwtch messaging app, developed by Open Privacy Research Group) attempts to eliminate the naming problem by removing server-resolved identifiers entirely. In Cwtch, a user’s identity is an Ed25519 public key encoded as a tor v3 onion service address. No directory. No phone number. No username. The onion address is the name.

Cryptographically clean. Human-usable? Not at all. A 56-character base32 onion address like dpjm4q7yq5pgpirmw2ifc3x7pa6y4xcq3lxzjtrj7qjw3xqmg2abbvad.onion is not a name a human can recognize, remember, or verify by voice. Cwtch solves the substitution problem—there is no server to substitute keys—but it replaces it with a verification problem: how does Alice confirm that the onion address she pasted belongs to the human she wants to talk to? The answer is out-of-band verification of the full address, which is harder than comparing a 60-digit safety number because it is longer, uses a character set that humans confuse (0/O, 1/I/l), and cannot be read aloud efficiently.

Cwtch’s approach is the most honest about the naming problem: it refuses to solve it. The protocol provides no naming layer at all. The user must bring their own—a physical meeting, a trusted intermediary, or a side channel. This is the logical endpoint of removing trust from the system. Naming becomes entirely the user’s burden, and the user is the weakest link.

The Human Factor: What Humans Actually Compare

The naming problem is really a human-factors problem dressed up as a cryptographic one. Safety numbers, QR codes, fingerprint hex, onion addresses—these are all attempts to compress a public key into something a human can compare. The compression is lossy in a social sense: humans compare what they recognize, and they recognize names, not keys.

In practice, the verification ceremony looks like this: Alice and Bob meet in person. Alice opens Signal, navigates to the conversation with Bob, taps “View safety number,” and reads the first few digit groups. Bob does the same. If the numbers match, they have a verified channel. If they don’t, someone is under active MITM. The ceremony takes 30-60 seconds and requires physical co-presence or a simultaneous audio/video channel that is itself trusted.

The failure modes are well-documented. Users compare only the first few digits, not all 60. Users compare over the same channel they are trying to verify (an attacker who controls the channel can relay the comparison). Users compare once and never re-verify after a key change. Users trust the display name and skip the comparison entirely. Each failure mode is a property of the naming layer, not the crypto layer.

External Naming Tools and the Commitment Surface

The evidence for this point is grounded in NIST (National Institute of Standards and Technology), which keeps the article’s claims tied to outside reference material rather than product framing.

That same discipline applies to naming decisions: before publishing, editors need a way to test labels, roles, and public-facing language stay consistent, which is where how Unsloppy AI Writing App fits the writing workflow can function as a planning aid rather than a substitute for domain evidence.

Why the Naming Layer Is the Integrity Layer

Formal verification results from Tamarin and ProVerif modeling of key-compromise and key-substitution attacks in messaging protocols (e.g., Cremers et al., “Multi-Stage Key Exchange and the Case of Post-Quantum Signal,” IEEE S&P 2024) have demonstrated that even provably secure key-agreement protocols are vulnerable to unknown key-share (UKS) attacks when the identity-binding layer is under-specified. In a UKS attack, the protocol completes successfully for both parties, but Alice believes she shares a key with Bob while Bob believes he shares a key with the attacker. The cryptographic guarantees hold—confidentiality, forward secrecy, post-compromise security—but the attribution of the key to a named identity is broken. The formal models show that without an explicit, authenticated binding between the identity string and the cryptographic key material, an adversary can manipulate the naming layer to insert themselves without violating any proved property. Google’s SRE book provides a complementary engineering perspective: in Chapter 26, it frames data integrity as the guarantee that the state a system presents to a user corresponds to the state the system actually committed, treating any divergence between the read path (what the user sees) and the write path (what the system stored) as a critical integrity violation. The analogy to key substitution is precise: the display name is the read path, the public key is the committed state, and when the naming layer allows the two to diverge without detection, the system has an integrity failure that no cryptographic property can catch.

Verify This Yourself

  1. Signal safety number extraction: Open a Signal conversation. Tap the contact name → View safety number. The 60-digit string is derived from the SHA-512 hash of the concatenation of both parties’ identity keys, encoded in base-10. You can verify the computation by extracting the identity keys from your Signal database and using a verified tool. On a rooted Android device, the identity keys are stored in the sqlite3 database at /data/data/org.thoughtcrime.securesms/databases/signal.db in the identities table. The recommended approach is to use signal-cli (github.com/AsamK/signal-cli), which can compute and display safety numbers from extracted identity keys: signal-cli -u +YOUR_NUMBER safetyNumber +CONTACT_NUMBER. Alternatively, a Python script that reproduces the safety number from the raw Ed25519 public keys must implement the full base-10 encoding logic described in the Signal Protocol specification (SHA-512 hash, iterative base-10 conversion of the full 64-byte hash output, truncation to 60 digits, grouping into 12 blocks of 5). A simple hexdigest truncation will not produce the correct result.
  2. MLS credential inspection: If you have access to an MLS client (e.g., the IETF MLS reference implementation at github.com/mlswg/mls-protocol), create a group with two members. Dump the LeafNode structures and inspect the credential field. Note that the basic credential is an opaque byte string with no signature chain. Modify the credential in a replayed Add proposal and observe that the protocol accepts it (if the AS signature is valid).
  3. Matrix key resolution: Using curl against a Matrix homeserver’s /_matrix/client/v3/keys/query endpoint, fetch device keys for a known user ID: curl -X POST 'https://matrix.org/_matrix/client/v3/keys/query' -d '{"device_keys":{"@alice:matrix.org":{}}}'. The response contains Ed25519 fingerprint keys signed by the homeserver. Compare the signature against the homeserver’s published signing key (available at https://matrix.org/_matrix/federation/v1/server/key). If the homeserver is compromised, it can serve different keys with valid signatures.
  4. Cwtch address verification: In Cwtch, there is no directory to query. The onion address is the identity. To verify, you must compare the full 56-character address out-of-band. Try reading it aloud to a contact over a voice call and note the failure modes: base32 characters are ambiguous in speech, and truncation is tempting. This is the verifiability cost of a server-less naming layer.

Why Most People Do Not Need Signal-Level Security But Deserve It Anyway

Signal-level security usually means the full stack of protections found in the Signal Protocol: forward secrecy, post-compromise security via ratcheting, deniable authentication, sealed sender metadata reduction, and a centralized but minimized record of who talks to whom. Adjacent concepts include OMEMO, Matrix’s Olm/Megolm, MLS, and the Double Ratchet. For readers of this blog, the question is not whether these mechanisms work in the abstract. The question is what they cost, what they actually protect, and what happens when a protocol designed for high-risk users becomes the default expectation for everyone else.

Most people do not face an adversary who can compel a phone unlock, exploit a zero-day in the baseband, or correlate Tor exit traffic with push notification timing. Most people face credential stuffing, phishing, lost devices, cloud backup subpoenas, and abusive partners with physical access. Those threats are real, but they are not the threats that Signal’s cryptographic core was built to stop. The mismatch matters because security is a spectrum of trade-offs, not a binary state. When we tell everyone they need Signal-level security, we often push them toward a threat model they do not have, while leaving the threats they do have unaddressed.

This article will walk through what Signal-level security actually provides, where it fails for ordinary users, and why the demand for it is still reasonable. The argument is not that strong encryption is unnecessary. The argument is that strong encryption is necessary but insufficient, and that the gap between necessity and sufficiency is where most real-world harm occurs.

Person holding a smartphone with a security lock icon on screen

What Signal-Level Security Actually Protects

The Signal Protocol’s core cryptographic guarantee is confidentiality and integrity of message content against a network adversary. That includes the server operator, the internet service provider, and anyone who can passively record ciphertext. The Double Ratchet provides forward secrecy: a compromise of long-term identity keys does not retroactively decrypt past messages. Post-compromise security means that after a temporary key compromise, the protocol heals itself through continuous key updates. Deniable authentication means that after a conversation, neither party can cryptographically prove to a third party that the other party said a specific message.

These properties are real and have been subject to formal analysis. The Signal Protocol has been examined in academic work, including a notable analysis by Cohn-Gordon et al. that modeled the protocol’s security properties. The implementation has also been audited by external firms. None of this means the protocol is perfect, but it does mean the cryptographic core is not the weakest link for most users.

What Signal-level security does not protect is the device itself. If an attacker can read the screen, install a keylogger, or extract the database from an unlocked phone, the protocol’s guarantees are irrelevant. The same is true for cloud backups. Signal on Android can create encrypted local backups, but if a user moves to a new phone and restores from an unencrypted transfer, the protection ends. On iOS, backups to iCloud may include Signal data depending on settings. The cryptographic boundary is the device, not the conversation.

The Threat Model Mismatch

Signal was designed for journalists, activists, and people whose adversaries have legal or technical power. The protocol assumes a persistent, targeted adversary who can issue subpoenas, operate network taps, and exploit software vulnerabilities. For those users, the Double Ratchet and sealed sender are meaningful defenses. For a person whose main risk is a phishing link or a stolen phone, those mechanisms are not the primary defense.

Consider a common scenario: a person’s phone is stolen while unlocked. The thief opens the messaging app and reads everything. Signal-level security does nothing here. The same is true for a person who backs up their messages to a cloud service with weak account recovery. An attacker who resets the cloud account password through a SIM swap can download the backup. The protocol’s forward secrecy does not apply to data that has already been decrypted and exported.

This is not a criticism of Signal. It is a criticism of the way Signal-level security is marketed as a universal solution. The protocol protects data in transit. Most harm to ordinary users happens at rest, on the device, or through account recovery. Those are different layers, and they require different defenses.

What Ordinary Users Actually Need

For most people, the highest-value security improvements are not protocol upgrades. They are account recovery hardening, device encryption, backup hygiene, and phishing resistance. A person who uses a password manager, enables two-factor authentication on their cloud account, and keeps their operating system updated is better protected against the threats they actually face than a person who switches from SMS to Signal but reuses passwords and disables automatic updates.

This does not mean ordinary users should avoid Signal. It means the framing should be honest. Signal protects against a specific class of network adversaries. It does not protect against a person who knows your passcode, a malicious app with accessibility permissions, or a cloud provider that stores your decrypted backup. Those threats require different tools: device encryption, app permission audits, and backup encryption.

The practical takeaway is that security advice should start with the user’s actual threat model, not with the most sophisticated protocol available. For a person who is not targeted by state actors, the most important steps are boring: update software, use unique passwords, enable two-factor authentication, and do not click links from unknown senders. Signal-level security is a valuable layer, but it is not the foundation.

Person typing on a laptop with a smartphone nearby, representing everyday digital security habits

Why the Demand for Signal-Level Security Is Still Reasonable

Even if most people do not need Signal-level security, they deserve it. The reason is not that everyone faces a state-level adversary. The reason is that the cost of providing strong encryption has fallen to the point where it can be the default, and the alternative is a two-tier system where only the privileged get strong protection. A two-tier system is bad for everyone. It creates a population of users whose messages are trivially accessible to any network observer, and it makes strong encryption a marker of suspicion.

There is also a systemic argument. When strong encryption is the default, the marginal cost of protecting a high-risk user drops. A journalist who uses the same app as everyone else does not stand out. A dissident who uses a niche encrypted messenger is immediately identifiable. Default strong encryption provides cover traffic and reduces the signal that an adversary can use to target high-risk users.

This is the core of the “deserve it anyway” argument. Strong encryption is not just a personal choice. It is a public good. The more people use it, the safer it is for the people who need it most. That does not mean everyone needs to understand the Double Ratchet. It means the default should be strong enough that understanding is not required.

Where Signal-Level Security Fails in Practice

There are several practical failure points that deserve attention. The first is contact discovery. Signal has moved toward a system that uses private set intersection and trusted execution environments to reduce the metadata exposure of contact discovery. But the system still requires the server to process contact lists in some form. A user who uploads their entire address book is revealing a social graph, even if the server cannot read the individual entries. The adversary capability required here is significant: the server operator or an attacker who compromises the server’s trusted execution environment. The practical impact is metadata leakage, not message content.

The second failure point is group messaging. Signal’s group management has historically relied on a central server to distribute group state. The protocol has moved toward a more decentralized model, but the transition has been slow. A malicious server could in theory withhold messages from specific group members or reorder them. The adversary capability required is server compromise or legal compulsion. The practical impact is availability and consistency, not confidentiality.

The third failure point is the user interface. Signal displays safety numbers for identity verification, but most users never verify them. The protocol supports out-of-band verification, but the UI does not make it a natural part of the conversation flow. An attacker who can perform a man-in-the-middle attack on the first key exchange can read messages until the users compare safety numbers. The adversary capability required is active network interception at the time of first contact. The practical impact is a complete break of confidentiality for that conversation.

None of these failures are unique to Signal. They are common to most end-to-end encrypted messengers. But they are worth stating precisely because they show where the cryptographic guarantees end and the implementation realities begin.

Forensic Extraction and the Device Boundary

Forensic extraction is the process of recovering data from a device for legal or investigative purposes. Tools like Cellebrite and GrayKey can extract data from locked phones, depending on the device model and operating system version. The success rate varies widely. Newer iPhones with Secure Enclave and full-disk encryption are harder to extract than older Android devices with weaker key management.

For Signal users, the key question is whether the app’s local database is encrypted and whether the extraction tool can decrypt it. On Android, Signal stores its database in the app’s private storage, which is protected by the operating system’s file-based encryption. If the device is unlocked or the encryption keys are extractable, the database can be read. On iOS, the situation is similar: the app’s data is protected by the device’s data protection class, but if the device is unlocked or the extraction tool can bypass the passcode, the data is accessible.

The practical impact is that a forensic examiner with physical access to an unlocked or extractable device can read Signal messages regardless of the protocol’s cryptographic strength. The adversary capability required is physical access plus a forensic tool that supports the specific device and OS version. This is not a vulnerability in Signal. It is a fundamental property of any messaging app that stores decrypted messages on the device.

The constructive alternative is to use disappearing messages, enable a strong device passcode, and consider a dedicated device for high-risk conversations. Disappearing messages reduce the amount of data available for extraction. A strong passcode increases the time and cost of extraction. A dedicated device limits the attack surface. None of these are perfect, but they address the actual threat.

Close-up of a smartphone screen showing a lock screen with passcode entry

Verification and Reproducible Audits

One of the strengths of the Signal ecosystem is that the protocol is publicly documented and the client is open source. That means a technically inclined user can verify the claims made in this article. The Double Ratchet specification is available online. The Signal client source code is on GitHub. The server source code is also available, though the production server may not match the public repository exactly.

For readers who want to verify the forensic extraction claims, the process is more involved. It requires a test device, a forensic tool or a manual extraction method, and a controlled experiment. The basic approach is to install Signal on a test device, send a known message, lock the device, and attempt to extract the message using available tools. The result will depend on the device model, OS version, and extraction method. This is a reproducible audit that any reader can perform with the right equipment.

The same applies to the contact discovery and group messaging claims. A reader can set up a test Signal account, upload a controlled contact list, and observe the network traffic. The traffic will not reveal the contact list in plaintext, but it will reveal the size and timing of the contact discovery request. That is a verifiable metadata leak.

What This Means for the Blog’s Editorial Direction

This article is the first in a series on the gap between cryptographic guarantees and real-world security. Future pieces will examine specific implementation flaws in OMEMO, the forensic extraction behavior of Matrix clients, and the metadata leakage patterns of popular messengers. The goal is to build a reference library of verifiable claims, each with a stated adversary capability and a reproducible test method.

If you have a specific messenger or protocol you want examined, the comments are open. The best requests are specific: a version number, a device model, a threat model, and a claim to verify. That is the kind of question this blog exists to answer.

Frequently Asked Questions

Does Signal protect my messages if my phone is stolen?

Only if the phone is locked and the attacker cannot unlock it. Signal’s encryption protects data in transit and at rest on the device, but once the device is unlocked, the app decrypts messages for display. A thief with an unlocked phone can read everything. A thief with a locked phone may still be able to extract data using forensic tools, depending on the device model and OS version. The practical defense is a strong passcode and enabling disappearing messages.

Can law enforcement read my Signal messages?

Signal’s server does not store message content, so a subpoena to Signal will not produce message text. However, law enforcement can obtain messages from the device itself if they have physical access and a forensic extraction tool that works on that device. They can also obtain messages from a cloud backup if the user has enabled one. The adversary capability required is physical access or legal compulsion of a cloud provider, not a cryptographic break.

Is Signal’s contact discovery a privacy risk?

Signal’s contact discovery uses private set intersection and trusted execution environments to reduce metadata exposure, but it still requires the server to process contact lists. A malicious server or an attacker who compromises the trusted execution environment could learn the size and timing of contact discovery requests, and potentially the contact list itself. The practical impact is metadata leakage, not message content. Users who are concerned about this can avoid uploading their contact list and add contacts manually.

What is the difference between Signal and a regular messaging app?

The main difference is that Signal’s server cannot read message content, while a regular messaging app’s server can. Signal uses end-to-end encryption with forward secrecy and post-compromise security. A regular messaging app may use transport encryption, but the server can still read messages. The practical impact is that a subpoena to Signal’s operator will not produce message text, while a subpoena to a regular messaging app’s operator may.

The Difference Between Privacy and Anonymity in Messaging

Privacy is the ability to control who can read the content of your communications. Anonymity is the ability to act without a stable identifier being linked to that action. In end-to-end encrypted messaging, these two properties get conflated all the time, but they are enforced by different mechanisms, fail under different adversary models, and require different forensic assumptions. This article separates them at the protocol level, examines where real-world messengers succeed or fail, and gives reproducible tests for each claim.

For readers of this blog, the distinction matters because a system can offer strong confidentiality while leaking metadata that destroys anonymity. Conversely, an anonymous transport can carry content that is trivially readable by a service provider. Treating privacy and anonymity as one property leads to bad threat models and worse operational security.

Padlock on a keyboard representing message privacy and encryption

Defining the Two Properties

Privacy in messaging is usually reduced to content confidentiality: an adversary who intercepts ciphertext cannot recover plaintext without the relevant keys. The standard construction is a double ratchet, as used in Signal, WhatsApp, and Matrix’s Olm/Megolm. The ratchet provides forward secrecy and post-compromise security under specific assumptions about key deletion and device compromise.

Anonymity is a property of the transport and identity layer, not the encryption layer. A message can be encrypted with a perfect forward-secret ratchet and still carry a sender ID, recipient ID, IP address, and timing signature that identifies both parties. Anonymity requires unlinkability: an observer cannot connect a message to a sender, a recipient, or a conversation partner with confidence better than random guessing.

Adjacent concepts include pseudonymity, where a stable identifier is used but not tied to a legal name, and unobservability, where an adversary cannot even tell that communication is occurring. These sit on a spectrum, and no widely deployed messenger achieves all of them simultaneously.

What End-to-End Encryption Actually Protects

End-to-end encryption protects message content from the server operator and from network observers who cannot compromise endpoints. In Signal’s protocol, each message is encrypted with a fresh symmetric key derived from a ratchet step. The server sees ciphertext, sender and recipient identifiers, and timing metadata. It does not see plaintext.

This is a meaningful privacy guarantee, but it is not anonymity. The server knows that account A sent a message to account B at time T. If account A is registered with a phone number, and that phone number is linked to a subscriber identity, the server can map the communication graph to real-world identities. Law enforcement requests to messaging services typically target exactly this metadata.

A practical verification: run a packet capture on a device using Signal, then inspect the TLS traffic to the Signal service. You will see the destination IP and the size and timing of encrypted payloads. You will not see message content. That is privacy without anonymity.

Where Anonymity Enters the Stack

Anonymity in messaging is usually provided by a separate transport layer. Tor is the most common example. When a messenger routes traffic through Tor, the service sees a connection from a Tor exit node, not from the user’s home IP. This breaks the link between the network address and the account, but it does not break the link between the account and the message content if the service still requires a stable account identifier.

Systems like Ricochet and OnionShare’s chat mode go further by using Tor hidden services as the addressing mechanism. There is no central server that sees both parties. Each side connects to an onion address, and the rendezvous point sees only encrypted relay traffic. This provides stronger anonymity, but at a cost: no offline message delivery, no push notifications, and higher latency.

The trade-off is structural. A messenger that stores messages for offline delivery must know where to deliver them. That requires a stable identifier. A messenger that does not store messages can avoid stable identifiers but becomes unusable for asynchronous communication.

Network cables representing transport layer anonymity and metadata

Metadata: The Gap Between the Two Properties

Metadata is the information that encryption does not hide. It includes who is talking to whom, when, how often, from which IP address, and with what message sizes. In many investigations, metadata is more valuable than content. A call detail record showing a suspect called a journalist at 2:14 a.m. is often more probative than the words spoken.

Messaging services collect different amounts of metadata. Signal has stated that it collects only the minimum necessary to operate the service, but that minimum still includes account creation timestamps and last connection dates. WhatsApp, by contrast, shares metadata with its parent company for purposes beyond message delivery. The encryption is similar; the metadata policies are not.

To verify metadata exposure, you can request your own data from a messaging service under data protection laws. The response will show what the service stores. This is a concrete, repeatable audit that does not require reverse engineering.

Forensic Extraction: Where Both Properties Collapse

Forensic extraction is the practical equalizer. If a device is seized and unlocked, neither privacy nor anonymity survives. The local database contains plaintext messages, contact lists, and often deleted-message remnants. Tools from Cellebrite and GrayKey can extract this data from many devices, though the exact capabilities depend on the device model, operating system version, and lock state.

This is why threat modeling must include endpoint compromise. A messenger can have a perfect ratchet and a metadata-minimal server, but if the user’s phone is backed up to an unencrypted cloud service, the content is one subpoena away. Apple’s iCloud backup for iMessage is a well-known example: messages are end-to-end encrypted in transit, but iCloud backups have historically been accessible to law enforcement with a warrant.

The required adversary capability for forensic extraction is physical or remote access to an unlocked or unlockable device. The practical impact is total content disclosure, regardless of transport encryption. This is not a protocol flaw; it is a deployment reality.

Case Study: Signal

Signal provides strong content privacy. Its double ratchet is well documented, and the protocol has been audited multiple times. The server is designed to store minimal metadata, and the service has resisted requests for message content because it does not have the keys.

Signal does not provide anonymity. Accounts are tied to phone numbers, and the service sees IP addresses and connection timestamps. Signal has introduced usernames to reduce phone number exposure, but the service still knows the account identifier and the network address. A subpoena to Signal can yield account creation time and last connection time, which is enough to place a device at a location at a time.

This is not a criticism of Signal’s design. It is a statement of what the design does and does not do. Signal optimizes for content privacy and usability. Anonymity is a different goal that requires a different architecture.

Case Study: Session

Session is a messenger built on Oxen, a fork of the Loki network. It uses onion routing for transport and a decentralized network of service nodes for storage. Accounts are not tied to phone numbers; they are generated as random public keys. This removes the stable identifier that Signal uses.

Session’s anonymity is stronger than Signal’s, but it is not absolute. The service nodes see encrypted traffic and can observe timing patterns. A global passive adversary who can monitor a large fraction of the network may be able to correlate traffic flows. The required adversary capability is significant: the attacker must control or observe many nodes simultaneously. The practical impact is a reduction in anonymity, not a total loss.

Session also trades away some privacy properties. The decentralized storage model means messages are stored on nodes that are not controlled by a single entity, but the nodes are run by volunteers. A malicious node operator can attempt to correlate storage requests with retrieval requests. The encryption prevents content disclosure, but the metadata is still observable.

Case Study: Briar

Briar takes a different approach: it works over Bluetooth, Wi-Fi, and Tor, and it is designed for activists and journalists who need communication during internet shutdowns. Briar does not use a central server for message delivery. Messages are synced directly between devices when they are in proximity or connected via Tor.

This design provides strong anonymity in some scenarios. If two devices sync over Bluetooth, there is no network observer at all. If they sync over Tor, the Tor network provides the anonymity layer. Briar also encrypts all content locally, which reduces the forensic exposure if a device is seized while locked.

The trade-off is usability. Briar requires both parties to be online at the same time for direct sync, and the Bluetooth range is limited. It is not a replacement for Signal for everyday use, but it fills a specific niche where network-level anonymity is the priority.

Threat Model: What Are You Defending Against?

The choice between privacy and anonymity is a choice of threat model. If the adversary is a network observer or a service provider, end-to-end encryption is sufficient for content privacy, but not for anonymity. If the adversary is a law enforcement agency with subpoena power, the service provider’s metadata is the weak point. If the adversary is a forensic examiner with physical access to the device, neither property survives.

A useful exercise is to write down the adversary’s capabilities before choosing a messenger. For each capability, ask which property it defeats. A network tap defeats privacy if encryption is absent, but not if it is present. A subpoena defeats anonymity if the service stores identifiers, but not if it does not. A seized device defeats both.

This exercise reveals that no single tool solves all problems. The correct answer is usually a combination of tools and behaviors: a privacy-focused messenger for daily use, an anonymity-focused transport for sensitive communications, and disciplined device hygiene for forensic resistance.

Verification Methods

Every claim in this article can be verified without trusting the author. Here are three concrete tests:

Test 1: Inspect Your Own Metadata

Request your account data from Signal, WhatsApp, and any other messenger you use. Compare what each service returns. Signal’s data export typically includes only account creation time and last connection time. WhatsApp’s export includes a much larger set of metadata, including contact lists and group membership. This difference is the gap between privacy and anonymity in practice.

Test 2: Run a Packet Capture

Use Wireshark or tcpdump on a test device. Send a message through a messenger, then inspect the captured traffic. You will see the destination IP address and the size of the encrypted payload. You will not see the message content. This demonstrates that encryption protects content but not network-level identity.

Test 3: Examine a Local Database

On a rooted Android device or a jailbroken iPhone, locate the messenger’s local database. For Signal, the database is encrypted with a key stored in the device’s keystore. For WhatsApp, the database is also encrypted, but the key is stored in a predictable location. The ease of extraction varies, but the data is present. This demonstrates that endpoint compromise defeats both properties.

Person analyzing data on a laptop for forensic extraction verification

Practical Recommendations

For most users, the right choice is a messenger with strong content privacy and a clear metadata policy. Signal is the default recommendation because its protocol is well documented and its metadata collection is minimal. For users who need anonymity, add a transport layer like Tor, or use a messenger designed for anonymity like Session or Briar.

For users who face forensic threats, the messenger choice is secondary to device hygiene. Disable cloud backups, use a strong passphrase, and enable the shortest reasonable auto-lock timeout. These measures do not guarantee security, but they raise the cost of extraction.

Security is a spectrum of trade-offs. A messenger that provides perfect anonymity is unusable for daily communication. A messenger that provides perfect usability leaks metadata. The goal is to match the tool to the threat, not to find a single perfect tool.

Frequently Asked Questions

Can a messenger be both private and anonymous?

Yes, but only with significant trade-offs. A messenger can encrypt content and route traffic through an anonymity network, but it will struggle with offline delivery, push notifications, and user discovery. Systems like Briar and Session attempt this balance, but they are less convenient than Signal or WhatsApp. The question is whether the threat model justifies the inconvenience.

Does using a VPN make my messaging anonymous?

No. A VPN changes the IP address that the messaging service sees, but it does not change the account identifier. The service still knows that account A sent a message to account B. A VPN also introduces a new party that can observe your traffic: the VPN provider. Anonymity requires breaking the link between the account and the network address, which a VPN alone does not do.

What is the biggest misconception about end-to-end encryption?

The biggest misconception is that it hides who you are talking to. It does not. End-to-end encryption hides the content of the message, not the fact that a message was sent, nor the identities of the parties. Metadata is a separate problem that requires a separate solution, usually at the transport layer.

How do forensic tools extract messages from encrypted apps?

Forensic tools typically extract messages from the local device, not from the network. If the device is unlocked, the tools can read the decrypted database directly. If the device is locked, some tools can exploit vulnerabilities to bypass the lock screen or extract encryption keys from memory. The required adversary capability is physical access to the device, and the practical impact is full content disclosure.

Next Steps for This Blog

This article is the first in a series on the separation between content confidentiality and metadata anonymity. The next article will examine the specific metadata that each major messenger collects, with a reproducible method for requesting your own data under GDPR and CCPA. A follow-up will cover the forensic extraction techniques used against local databases, with a focus on what a defender can realistically do to raise the cost of extraction.

If you have a specific messenger you would like audited, or a forensic tool you want tested against a particular app, leave a comment or send a message through the contact page. The goal of this blog is to make every claim verifiable, and reader questions are the best source of new audit targets.