Stealth thesis
Why the userbot fleet is read-only by construction, and how the guard enforces it at runtime + in CI.
Stealth is sacred. The product exists because targets cannot detect it. Every shortcut that erodes that property erodes the product.
Visibility classes
The userbot cluster has exactly three visibility classes:
Zero-visibility — allowed
import_contacts— never notifies the imported number.getFullUser,getUser,getCommonChats— RPC reads only.- Receiving
UpdateUserStatusfrom a chat we share with the target. getHistoryin a shared chat.- Media download.
Passive-visibility — allowed only if persona is plausible
- The userbot appears in member lists of chats it has joined.
- Mutual contacts can resolve the userbot.
- The userbot's own online status is visible to people it has chatted with.
Active-visibility — absolutely forbidden
| Method | Why |
|---|---|
stories.incrementStoryViews | Bumps the view counter the target sees. |
stories.readStories | Same — the target can see who's read. |
messages.sendReaction | The reaction is signed; target sees it. |
messages.sendMessage | Obviously visible. |
messages.editMessage | Visible. |
messages.forwardMessages | Recipient sees forward attribution. |
phone.requestCall, phone.acceptCall | Triggers a ringtone. |
channels.inviteToChannel | Sends an invite. |
messages.addChatUser | Adds to group, target sees the system message. |
messages.startBot | Triggers a bot the target may own. |
messages.setTyping | The "..." indicator the target sees. |
contacts.acceptContact | Target sees you in their contacts. |
messages.markDialogUnread | Visible to the target. |
Runtime enforcement
apps/userbot/stealth/guard.py wraps every Pyrogram Client with
assert_stealth_safe(method, params). The forbidden list is whitelisted
in core/policies/stealth_safety.py and regenerated from
config/stealth_whitelist.yaml.
Any call to a forbidden method raises StealthViolation. The exception
is never caught and swallowed — it propagates, fails the operation,
pages the owner via Telegram, and lands in audit_log with severity
critical.
CI enforcement
scripts/stealth_whitelist_check.py AST-scans apps/userbot/ and fails
the build if any Pyrogram method is invoked that isn't whitelisted with a
justification comment.
tests/stealth/ requires 100 % line coverage of
apps/userbot/stealth/ and asserts that calling any forbidden method
raises StealthViolation — no mocking allowed.
Humanizer rate limits
Defaults — owner can tighten, cannot lift:
| Constraint | Limit |
|---|---|
| Chat joins | ≤ 3/hour, ≤ 10/day |
| Contact imports | ≤ 5/hour, batched |
| Messages sent/day | 0 — absolute, non-tunable |
| Reactions placed/day | 0 — absolute, non-tunable |
| Profile updates | ≤ 2/month |
| API requests | ≤ 4 rps sustained, ≤ 15 rps burst |
If a workflow seems to require sending or reacting, the workflow is wrong.
The three protection layers for any Telegram user
- System protection — always on. Owner, admins, and userbot accounts
are listed in
protected_users; any attempt to add them as a target returns a generic "user not available". - Stealth Mode (paid opt-out) — 99★ / 249★ / 799★ / 4999★ for 1 mo / 3 mo / 1 y / lifetime. Blocks new tracking, seals history to existing subscribers, disables reverse lookup, optional alerts on attempted adds.
- Regulatory data-subject erasure (ops-only) — GDPR/CCPA flow handled out-of-band by the operator through the API. Not a self-service button.
Every code path that adds a target calls assert_can_track(target_id)
before any RPC.