Open-source project
drego85/tosint avatar
drego85/tosint

tosint: a single file Telegram profiler for investigators and DFIR work

Tosint is a Telegram OSINT tool that extracts actionable intelligence from bot tokens and chat IDs for security investigations.

877 stars90 forksPythonGPL-3.0

At a glance

What is it?
Tosint is a GPLv3 Python tool that takes a Telegram bot token and a chat id and turns them into a structured report, covering bot capabilities, webhook infrastructure, chat policy flags and administrator rights, with message and media export for forensic collection. The judgement is that the careful framing of what the API can and cannot tell you is the most valuable part of the documentation, and that the export is only ever as complete as the session that produced it.
Who is it for?
Tosint fits a threat analyst or digital forensics investigator who already holds a bot token for a campaign under investigation and needs a written profile of that bot and the chats it sits in, plus a defensible export of what the session can reach.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 23 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What a bot token reveals, and what it does not

The bot section of the report is built from read-only API calls, and the documentation is careful about the limits of each field. You get the bot identity, its first name, username and user ID, and a capability signal in the form of can_read_all_group_messages, which is true when privacy mode is disabled, and the README is explicit that a false value does not mean the bot cannot read any group messages. You also get profile metadata through getMyDescription and getMyShortDescription, and the default requested administrator rights for groups and for channels, with the note that these are not the actual rights in the target chat. The bot's status in the target chat comes from getChatMember, with roles such as administrator or member. Webhook infrastructure is read with getWebhookInfo, giving the configured URL, IP address, pending updates and delivery errors, and here the documentation draws a line that matters during an investigation, since an empty URL means no webhook is configured and does not identify the polling server. Registered commands come from getMyCommands, limited to the default scope and language and not a complete inventory, and the default menu from getChatMenuButton, where chat specific overrides are not queried. Results are preserved in JSON under bot.webhook, bot.commands and bot.menu_button, failed enrichment calls are reported without stopping the rest of the analysis, and optional fields are omitted from the text output when Telegram does not return them, so their absence must not be read as false.

Chat intelligence and the second getChat call

The chat section starts from getChat and reads the core metadata: title, type, ID, the username and the active usernames, the description normalised to a single line, and the visibility and policy flags when they are available. That last group is where the interesting configuration lives, covering visible history, hidden members, protected content, join by request, slow mode and the auto delete timer. The tool also reports the linked chat ID, and if that value is present it performs a second getChat call to enrich the linked chat, which is how a channel that is officially linked to a discussion group gets both sides described. Invite links are handled in two ways, the existing invite link if Telegram exposes it, and an optional additional link created through createChatInviteLink behind the --create-invite-link flag, which is the one write operation in the tool and is off unless you ask for it. Member count comes from getChatMemberCount.

Administrators, bots included

Administrator enumeration comes from getChatAdministrators, and each entry is printed with an index, the first and last name, the user ID, the username, a bot flag, the role or status such as creator or administrator, the custom title if one is set, and the granular admin permissions including the can_* family and is_anonymous. The bot flag is the part that makes this useful for threat work, because a bot holding administrator rights in a channel is a meaningful finding, and Tosint requests return_bots=True so that other bot administrators appear in the list alongside the humans. The lookup is skipped for private chats, since a direct conversation has no administrator list in the same sense, and the report reflects the role the account holds at the time of the query rather than a historical record.

Text, JSON, and two export formats

Output comes in two flavours. By default you get formatted text, --json switches to JSON only on stdout with no text output, --json-file <path> saves a JSON report to a file, and using both gives you JSON on stdout and a copy on disk. Message exports use a minimal TXT format and a richer JSONL format, and the difference between them is where the forensic value sits. Only JSONL carries the source chat_id, UTC message and edit timestamps, the reply message ID, a per message acquisition timestamp named acquired_at, the original attachment name, the MIME type, the Telegram file size, the file identifiers and the downloaded file size in bytes. Unavailable fields are null, and the metadata is retained even when attachment downloads are skipped. Timestamps are normalised carefully, since Pyrofork's naive local timestamps are converted to UTC including the daylight saving offset applicable to the message date, while the TXT format keeps local time with an explicit UTC offset, in the shape 2026-09-30T12:40:35+02:00. SHA-256 hashing of downloaded media is disabled by default and enabled with the --hash-media flag, and hashing reads each whole file in chunks, which adds time on large downloads, while a hash failure is recorded without turning a successful download into a failed one.

An export is only as good as the session behind it

This is the section to read before you quote any number from a report. Exports contain only messages Telegram makes available to the authenticated bot or user session, deleted or inaccessible messages cannot be guaranteed to be recovered, and different sessions may have access to different content, so two investigators running the tool on the same chat can legitimately produce different exports. The idscan mode has its own vocabulary and the README spells it out, since Message IDs Scanned counts requested IDs rather than existing messages, while Unavailable Message IDs counts IDs for which no dated message was returned, which does not prove deletion. Progress in that mode uses ids_scanned and unavailable_ids, while history mode counts the messages Telegram actually returned. The JSON report keeps the older messages_scanned key for compatibility and adds unavailable_message_ids for the ID scan count, so scripts written against the earlier key keep working.

Installing it and supplying API credentials

The tool is a single Python file with a small dependency set, and the installation is a clone plus a virtual environment:

bash
git clone https://github.com/drego85/tosint.git
cd tosint
bash
python3 -m venv venv
source venv/bin/activate
python -m pip install -r requirements.txt

The requirements are pinned, with requests at 2.34.2, pyrofork at 2.3.69 and tgcrypto at 1.2.5, and the README notes that tgcrypto is optional from a functional perspective but strongly recommended for much faster MTProto upload and download performance. The MTProto download features need your own Telegram API_ID and API_HASH, taken from the official Telegram guide, and those two values can live in a local .env file for faster repeated analysis or be entered interactively at runtime:

dotenv
TELEGRAM_API_ID=123456
TELEGRAM_API_HASH=0123456789abcdef0123456789abcdef

Only those two values are read from the .env file, and bot tokens and chat IDs must be provided through the command line, which is a deliberate separation between the account credentials and the investigation target.

A young repository with one release and clear boundaries

The repository is small and shaped around one script. The top level holds tosint.py, the requirements file, a tests directory, a LICENSE.md file and the GitHub configuration, with no package structure, no plugin system and no configuration file, so reading the code is a realistic way to understand exactly what it sends to Telegram. The licence is GPLv3, which is a sensible choice for a tool that investigators may want to extend with their own enrichment steps. The release history has one entry, v1.0.0 on 2026-09-30, and the last push was on 2026-09-30, with the repository not archived, so the project is at the stage where the interface may still move. The README also includes a legal and ethical section that states the tool is intended for lawful investigative, research, DFIR and threat intelligence activities and must not be used for illegal activities or unauthorised access or anything that violates Telegram's terms of service, and given what the tool does with a token, that paragraph is part of the documentation rather than a disclaimer.

Editorial conclusion

Tosint fits a threat analyst or digital forensics investigator who already holds a bot token for a campaign under investigation and needs a written profile of that bot and the chats it sits in, plus a defensible export of what the session can reach. It is the wrong choice for anything outside that frame, since the README's legal and ethical section rules out unauthorised access and illegal use, and it is a poor fit if you need historical message recovery, because the export only ever contains what Telegram still serves to the authenticated session. Before you run it, confirm you are authorised to hold the token, read the privacy mode caveat next to the can_read_all_group_messages flag, and plan to keep the JSON report as evidence with its acquisition timestamps intact.

Frequently asked questions

What does tosint extract from a Telegram bot token?

Bot identity, the can_read_all_group_messages capability flag, the bot descriptions, its default requested administrator rights, its status in the target chat, webhook information from getWebhookInfo, registered commands and the default menu button. These are read-only API calls, and the results are kept in JSON under bot.webhook, bot.commands and bot.menu_button.

What does the JSONL export contain that the TXT export does not?

Only JSONL carries the source chat_id, UTC message and edit timestamps, the reply message ID, a per message acquired_at timestamp, the original attachment name, the MIME type, the Telegram file size, the file identifiers and the downloaded file size in bytes. The TXT format stays minimal, with local time and an explicit UTC offset.

Can tosint recover messages that have been deleted?

No. Exports contain only messages Telegram still makes available to the authenticated bot or user session, and deleted or inaccessible messages cannot be guaranteed to be recovered. In idscan mode the Unavailable Message IDs count means no dated message was returned for those IDs, which does not by itself prove deletion.

Official sources

  1. drego85/tosint on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/drego85-tosint.svg)](https://hysenlabs.com/projects/drego85-tosint)

Was this useful?