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 byAccount::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 isreadMapWith(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 fromFileKeyvalues (for examplemap0,map1,maps,configs, and per-feature keys such aslskDrafts,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:
- Without the passcode, an attacker who copies
tdatacannot recover the authorization key frommapby reading the file. The key is encrypted under a key derived from the passcode and the stored salt. - 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
tdatadirectory 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:
- Install Telegram Desktop on a test account. Log in. Confirm the account works.
- Close the client fully. Locate the
tdatadirectory (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). - Copy the entire
tdatadirectory to a second machine. - Install the same or a compatible version of Telegram Desktop on the second machine. Place the copied
tdatawhere the client expects it. - 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
tdataas 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.