Skip to content

Threat model ​

What this framework protects, from whom, and what it explicitly does not protect. The safety gate in ROADMAP.md requires this document and its release checklist to stay current; the per-surface findings, the fixes made and the residual risks live in Security.

Assets ​

AssetWhy it mattersWhere it lives
Session credentialsA WhatsApp/Telegram/IMAP session is the account: leaking it hands over the identitysessions/, *_sessions/, provider config, baileys_store.json
Bot secretsProvider tokens, API keys, webhook secrets, app secretsEnvironment/.env, provider config, BotConfig
Message content and mediaPersonal data of the end users (bodies, captions, attachments, locations)Store, checkpoints, journal, logs, traces
Operational dataMulti-tenant configs, campaign recipients, inbox notes, gate runsmanager, deployments, inbox, crm, campaigns, hub
Tenant boundariesOne customer must never read or drive another customer's botNamespaces, store keys, REST /v1, tenant-kv
Bot availabilityA hung or flooded bot is a business outage and, on WhatsApp, a ban riskIngress, dispatcher queues, rate limiter

Trust boundaries ​

flowchart LR
  subgraph untrusted[Untrusted]
    P[Platform webhooks / sockets]
    U[End users]
    L[LLM providers and tools]
    A[MCP clients / coding agents]
  end
  subgraph edge[Edge - this framework]
    S["@botmesh/server<br/>raw body, limits, timeouts"]
    V[Provider signature check]
    D[Dispatcher + access lists]
    C[Core runtime]
  end
  subgraph trusted[Operator-controlled]
    ST[(Store / durability)]
    OP[Bot code, plugins, flows]
  end
  P --> S --> V --> D --> C
  U --> P
  L --> C
  A -->|stdio| OP
  C --> ST
  OP --> ST

Trusted: the operator's bot code, plugins and flows, and the machine the process runs on. Untrusted: every platform payload, every end-user message, every model answer, every byte fetched from a URL that came from a payload, and any MCP client that talks to @botmesh/mcp.

Threats and controls ​

#ThreatSurfaceControlResidual risk
T1Forged webhook (fake message or call)13 channelsPlatform signature over the raw body, constant-time comparison, provider refuses to start without credentialsReplay where the platform signs no timestamp (see below)
T2Payload flood / oversized bodyWebhook ingress@botmesh/server limits body size, per-body and ingest timeouts, concurrency cap, 413/408/503The operator still sizes the process and the reverse proxy
T3SSRF from a user-supplied URL (media, TTS, embeddings)Every outbound fetchsecureFetch: HTTPS, private ranges rejected, socket pinned to the checked IP, redirects re-validated, size/time capsDNS answers can change after the check only if a provider bypasses secureFetch
T4Path traversal through ids (tenant, bot, chat, flow)REST /v1, manager, MCP docsIds restricted to [A-Za-z0-9][A-Za-z0-9_.:-]{0,63}, filenames derived from them, docs paths resolved and rejected outside the rootNone known
T5Code execution from a stored flowJSON flow documentsData-only schema: no code, no module import, no eval; safe expression grammar (no regex, no prototype access, bounded length/depth); http step goes through secureFetchAn http step can still call a public endpoint the operator allowed
T6Cross-tenant read/writeStore, manager, product packagesNamespace per bot, tenant-scoped keys in tenant-kv, compare-and-set, REST scopes and 404 for other tenantsA custom IStore implementation can break its own isolation
T7Secret or personal data in logs/tracesLogger, OpenTelemetryNo bodies, prompts, QR payloads or tokens in framework logs; spans carry ids through the ids policy (hash by default) and never message contentOperator code that logs ctx.body
T8Prompt injection driving tools@botmesh/aiTools are opt-in per call, destructive ones need confirm: true, the model cannot invent tool ids (tools: ['id'] filters the configured set)A read-only tool can still leak whatever the operator gave it
T9Untrusted code inside the processPluginsPlugin.install is synchronous, plugins only get the scoped facade, no sandboxPlugins run in-process with full Node permissions: install only code you trust
T10Ban of the WhatsApp numberBaileys / gatewaysOpt-in rate limiter, typing/pacing, no button spam, exclusiveSession for single-connection transportsAutomating WhatsApp Web is unofficial and always carries ban risk
T11Agent reads or writes something it should not@botmesh/mcpLocal stdio only (no network listener), read-only tools, no eval, docs reads confined to the configured root, no writes to diskThe client decides what to do with the answers
T12Replay of a captured webhookMeta, Telegram, Twilio, HighLevel, Gupshup, WPPConnectPlatform id dedupe in memory + store-backed dedupe windowNo platform timestamp to enforce a window; keep endpoints on HTTPS

Assumptions ​

  • HTTPS terminates at the operator's reverse proxy or platform; the process itself speaks plain HTTP on the loopback interface.
  • The machine is not shared with untrusted users: plugins and bot code are trusted.
  • Secrets arrive from the environment; the framework never reads .env on its own.
  • The operator's store is authenticated and not reachable from the internet.

Out of scope ​

  • Multi-tenant authentication beyond the manager's tokens (no OIDC, no RBAC).
  • Hardening of the operator's host, container, database or reverse proxy.
  • WhatsApp / Meta / Telegram / Twilio terms of service compliance, and the legal basis for processing end-user data.
  • Denial of service above the ingress limits (network layer).
  • Model quality, hallucinations or vendor data-retention policies.

Reporting ​

Open a private advisory through SECURITY.md; never a public issue. A fix lands with a regression test named security-audit in its package.

Released under the MIT License.