A member of a private group I run was removed for inactivity. A few weeks later, they were back in the group. Nobody had approved them.

How they got in

New applicants go through a small bot. When I approve one, the bot creates a one-time invite link and sends it to them. That link has a usage limit of one. I assumed that meant it died after it was used.

It doesn’t, quite. The removal flow deletes the member’s data and kicks them, but nothing ever revoked the link. Telegram’s admin log showed the “new” join came through an invite created weeks earlier, still marked as active. The person had simply opened the old link again.

The fix that didn’t work

My first version of the cleanup asked my own account to revoke the stale links. Every call failed with the same error: normal users can’t edit invites that were created by bots. Only the bot that created a link can revoke it.

So the cleanup now borrows the creating bot’s identity for that one call. It runs:

  • when someone joins (their link has done its job),
  • when someone is removed or leaves,
  • every night, as a sweep over every active link,
  • and every minute, for anyone Telegram has seen in the group, in case a join and a leave both happened between two checks.

The first sweep revoked more than twenty links. One slipped through anyway: it had been created under an older naming scheme (gatekeeper-… instead of connector-…), so my pattern didn’t match it. I only found it by listing what was still active and reading the names.

  • A returning member’s profile came back without one field, so a headcount I track by profile came out off by one. Their old application had been purged on removal. Now that field (and the photo) are restored from the archived copy.
  • An applicant said they’d filled the form but I never saw it. The bot only writes the application after the photo arrives, so a half-finished form simply vanished. There is now a chat-based fallback, and the bot tells me when someone has been stuck for ten minutes.

What I’d tell my past self

A one-time link isn’t a one-time permission. Anything that grants access needs an explicit end of life tied to the person, not just to the first click. And when a cleanup relies on a pattern match, list what is actually left afterwards, because the thing you missed is the thing your pattern didn’t describe.