Trust

Security overview

How we protect your data, your bot tokens, and your subscribers. Last updated: May 17, 2026.

Infrastructure

  • Front-end: Vercel edge network, EU primary region.
  • Back-end: Railway-managed Python application, EU region (Frankfurt / Amsterdam).
  • Database: Railway-managed PostgreSQL with daily automated snapshots, 30-day retention.
  • Transport: TLS 1.2+ everywhere, HSTS preload, HTTP/2.
  • Headers: strict CSP, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin.

Authentication

  • Email verification required before first login. Verification codes expire after 15 minutes and are single-use.
  • Passwords: bcrypt with per-row salt, cost factor 12.
  • Session: signed JWT in HttpOnly, Secure, SameSite=Lax cookie, 30-day rolling expiry.
  • Per-IP rate limiting on /api/auth/login and /api/auth/register — repeated failures throttle the IP and the targeted account.
  • Optional IP allow-list (WEB_ALLOWED_IPS) for high-security single-tenant deployments.

Authorization & tenant isolation

  • Every bot-scoped endpoint resolves the bot from the URL slug, then verifies the authenticated user is the owner or a granted member via BotPermission.
  • Database-level isolation: every tenant table carries a bot_id column and a SQLAlchemy ORM event auto-injects WHERE bot_id = current_bot_id on every SELECT. Mis-routed queries can never leak rows across bots.
  • Cross-tenant requests return 403 — never 404 — so we don't leak the existence of other bots.

Bot tokens & webhooks

  • Bot tokens are encrypted at rest with Fernet (AES-128-CBC + HMAC-SHA256) keyed off the WEB_SECRET_KEY environment variable. Decrypted only in-memory at send time.
  • Tokens are validated against Telegram's getMe before being persisted — invalid tokens are refused.
  • Every webhook URL carries a per-bot webhook_secret. We verify the X-Telegram-Bot-Api-Secret-Token header on every inbound request; mismatches return 403 and are not processed.
  • Setting or rotating a bot token regenerates webhook_secret automatically so the old secret becomes useless.

Payments

  • Card details never reach our servers — Stripe Checkout handles capture and we only persist Stripe customer / subscription IDs.
  • Stripe webhook signatures verified with STRIPE_WEBHOOK_SECRET on every event; mismatches return 400.
  • Payment-disputes and refund history live in your Stripe Customer Portal — accessible from Account → Subscription → Manage billing.

Concurrency & data integrity

  • Broadcasts use a Postgres partial-unique-index lock (UNIQUE ON broadcasts(bot_id) WHERE status='sending') — two admins clicking Send simultaneously can't double-deliver. Stale ‘sending’ rows older than 10 minutes are auto-released.
  • Edits use optimistic concurrency: PATCH endpoints accept if_unmodified_since and return 409 if the row moved on us. Each campaign / auto-message / scheduled broadcast carries an updated_at token.
  • Scheduler skips read-only bots, bots without tokens, and paused auto-messages — three independent gates against accidental sends.

Audit logging

Every mutating action writes an immutable row in audit_logs: who, what, which resource, IP address, user-agent, full details JSON. Retained for 2 years. Visible to the bot owner under Audit Log.

Monitoring & incident response

  • Health endpoint /healthz exposed for uptime probes.
  • Application errors stream to Sentry with PII payloads scrubbed.
  • Database backups verified by automated restore drill weekly.
  • Critical-severity incidents trigger pager rotation; users informed via in-app banner + email.

Responsible disclosure

Found a vulnerability? Please email security@myskua.com. We respond within one business day. Please give us at least 30 days to remediate before public disclosure. We don't currently run a paid bug-bounty programme but we credit researchers in our security hall of fame on request.

What we ask of you

  • Use a strong, unique password — a manager helps.
  • Don't paste your bot token into public channels. If a token leaks, rotate it from Platform → Edit bot → Telegram token.
  • Review the audit log periodically. Anything unfamiliar ⇒ rotate password and email security@myskua.com.

See also: Privacy Policy · DPA · Terms of Service.