Skip to the content

IT&SOFT4 min readSecurity

5 vulnerabilities we find in 8 out of 10 Telegram bots

An unverified signature, other people’s orders by walking the ids, secrets in the repository. Five findings that turn up in production more often than anything else.

We have checked bots and Mini Apps on audits and on our own pilots. The order below follows how often we find each one. The most common item here is also the dullest.

1. The initData signature is not verified

A Mini App receives data about the user in an initData string signed with the bot token. Verifying it takes fifteen lines of code. It is skipped in roughly half the cases—because in development everything works without it.

The consequence: anyone with curl can place an order, spend loyalty points or read the history under an arbitrary user_id. No hacking involved, just an HTTP request.

Verification belongs on the server, on every request. Doing it once when the application opens is not enough. And look at auth_date separately: a signed string from a week ago is a valid signature and an invalid session.

2. Direct access to other people’s objects

The OWASP classic at number one, and in bots it appears in almost unchanged form. An endpoint like /api/orders/1042 returns the order by id, and there is no check that “this order belongs to this user”.

The identifiers are sequential, so dumping the entire order database is a ten-line loop. We have pulled delivery addresses, phone numbers and amounts that way.

The cure is not obfuscating identifiers (UUIDs barely help here) but an ownership check in the data access layer: the query always carries where user_id = ..., and it is not forgotten because otherwise it does not compile.

3. The bot token and acquiring keys in the repository

.env in git, keys in docker-compose, the token in the source “just while debugging”. A private repository is not protection: contractors change, forks remain, and history is not deleted along with the file.

The bot token lets anyone read every message and write as the bot to everyone who has ever talked to it. An acquiring key lets them initiate refunds.

What to do: secrets only in environment variables, an .env.example with no values in the repository, a secret scanner in CI. If a token has ever been in the history, revoke it. Deleting the file achieves nothing.

4. No rate limiting

The bot takes enquiries; each enquiry sends a Telegram notification and writes a row to the database. There are no limits. One script creates ten thousand enquiries in a minute, the manager receives ten thousand notifications, the database grows and real enquiries are lost in the noise.

No data leaks here, but the business process stops, and clearing up takes longer than the attack did.

The minimum: a limit per user id and per IP, a honeypot field in the forms, a check on the minimum time taken to fill a form in. A captcha is a last resort; it costs conversion.

5. A payment webhook with no signature check

The provider sends a notification that a payment succeeded. The handler trusts the request body and moves the order into the paid state. The webhook address can be read from the frontend or guessed—it is rarely secret.

After that anyone at all sends a POST and gets the goods for free.

What has to be verified is the signature of the notification, and on top of that you request the payment status from the provider’s API before shipping anything. The notification is a “go and check” signal.

What is not on this list

No exotica: chains of three vulnerabilities, race conditions, supply chain attacks. They exist, we find them occasionally, but they are not what happens to eight bots out of ten.

Eight out of ten break on the things listed above, and all five are closed in about a day of work. At the start that is a day. After an incident it is a week and a conversation with your customers.

How to check your own bot in an hour

  1. Send a request to the bot’s API without initData—does it answer.
  2. Take your own order id, subtract one, request it—see what comes back.
  3. Search the repository history for the strings bot, token, secret, key.
  4. Send a hundred requests in a row—does anything push back.
  5. Send a payment webhook by hand with a valid body and a wrong signature.

If even one of them goes through, the vulnerability is already there. You are unlikely to be the first person to find it.

ShareTelegramVK
Author

IT&SOFT

A small team of engineers. We write about the work we do by hand, and about what breaks while we do it. If you have something similar on your plate, write to us and we will go through your case.

Discuss your task
Subscribe to new breakdowns
Next

Got a similar
task?

Describe it in the brief. In working hours we come back with an estimate of time and cost within two hours.