Skip to content

fix(security): Encrypt Slack and Telegram bot tokens at rest (Invariant #13) #453

Description

@vybe

Problem

Bot tokens for external messaging integrations are stored as plaintext in SQLite, violating Architectural Invariant #13 (Credentials: never stored in DB; transient secrets in Redis; encrypted exports use AES-256-GCM).

Confirmed plaintext storage

  • slack_link_connections.slack_bot_token — TEXT NOT NULL (src/backend/db/schema.py:539, db/migrations.py:537)
  • slack_workspaces.bot_token — TEXT NOT NULL (db/migrations.py:863)
  • telegram_chat_links bot tokens — plaintext (see adapters/telegram_adapter.py and db.get_telegram_bot_token)

Writes happen in db/slack.py:create_slack_connection and matching Telegram paths without any encryption layer.

Architecture doc is inaccurate

docs/memory/architecture.md claims slack_workspaces stores "encrypted bot tokens (encrypted at application layer)" — this is false and should be corrected as part of this fix.

Impact

Slack/Telegram bot tokens grant full workspace messaging access. A DB leak (backup exfil, SQLite file access, read-only replica exposure) reveals live credentials that can impersonate Trinity agents in user workspaces. Trinity already has an encryption primitive: services/credential_encryption.py (AES-256-GCM, used for .credentials.enc).

Scope

  • Encrypt bot tokens at write, decrypt at read for:
    • slack_link_connections.slack_bot_token
    • slack_workspaces.bot_token
    • Telegram bot token storage (telegram_chat_links or equivalent)
  • Reuse services/credential_encryption.py (AES-256-GCM) or add an equivalent helper keyed off SECRET_KEY / dedicated env var.
  • Migration strategy for existing rows:
    • Option 1: one-shot migration that encrypts in place at startup (needs versioned migration in db/migrations.py).
    • Option 2: lazy migration — encrypt on next write, tolerate both formats on read. Simpler but leaves plaintext around until rotation.
  • Update docs/memory/architecture.md to reflect actual state (either correct the "encrypted" claim with the real implementation, or remove it if Option 2 lazy migration).

Acceptance Criteria

  • Bot tokens for Slack (both tables) and Telegram are encrypted at rest
  • Existing rows migrate cleanly (no service disruption after backend restart)
  • Tests cover: create → read round-trip, decryption failure handling, legacy plaintext row migration (if one-shot approach)
  • architecture.md credentials section is accurate
  • /validate-architecture no longer flags slack_bot_token under Invariant feat: SMARTS trading pipeline with Telegram notifications and Miro visualization #13

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions