Skip to content

Threat Models

  • API keys are encrypted in the database with pgcrypto. A full DB dump is useless without the CRYPTO_SECRET. If the host or secret is compromised, rotate all provider keys immediately.
  • SQL injection is defended by Bun SQL template literals. This only holds as long as developers keep using them, so please never concatenate raw values into queries.
  • Discord roles are the trust boundary. ManageGuild = admin power. A misconfigured Discord role is a real privilege escalation.
  • LLM output is untrusted. Prompt injection through memories, documents, web pages, or MCP tool descriptions is a real attack surface, use /tool prompt snapshot to check source of malicious prompts.
  • MCP servers run with host-level trust. A malicious local MCP server owns the machine. Only run MCP servers you trust, under least-privilege OS accounts.
  • BYO endpoints can see your data. Custom text, image, TTS, and STT endpoints receive the full request payload. This is inherent, endpoint operators own that risk.
  • SSRF is mitigated by fetchUserRemoteUrl() and safeDownload(). New code touching user-supplied URLs must use these helpers as skipping them is a SSRF hole.
  • Set quotas, enable BYOK mode, and disable feature flags (image gen, video gen, cross-channel messaging, manage-message, prompt snapshot) unless you actually need them to prevent users from abusing your key’s rate limits.

This document outlines the threat model for TomoriBot using the STRIDE framework and groups risks by attack vector.

Related reference:

  • docs/subsystems/security.md
  • docs/pipelines/tool-loop/ (tool-loop pipeline reference)
  • docs/integrations/matrix-bridge.md
  • docs/integrations/voice/README.md

1. Database, Secrets, and Tenant Isolation

Section titled “1. Database, Secrets, and Tenant Isolation”

TomoriBot stores server configuration, personas, memories, API credentials, managed webhook tokens, Matrix links, custom endpoints, quota state, reminders, and caches in PostgreSQL.

Threat (STRIDE)ScenarioRiskCurrent MitigationImplementation AreaResidual Risk / Assumption
Tampering / Elevation of PrivilegeSQL injection through Discord messages, slash command options, persona text, imported presets, memories, or endpoint settings.CriticalBun SQL tagged template literals for values. Dynamic update field names are constrained by schema-derived allowlists.src/utils/db/client.ts, src/utils/db/sqlSecurity.ts, src/utils/db/repositories/*, src/utils/db/repository*Sql.tsDevelopers must keep using parameterized SQL and the field-validation helpers for dynamic column names.
Information DisclosureCross-server or cross-user leakage from a missing server_id, user_id, persona_id, persona lineage, or Discord channel filter.HighApplication-layer tenant scoping is embedded in DB helpers and command handlers. Personal/server memory paths are separate, and many export/delete operations are scope-specific.src/utils/db/*, src/commands/memory/*, src/commands/personal/*, src/commands/server/*There is no database row-level security policy; correctness depends on query scoping and review.
Information DisclosureAPI keys or webhook tokens leak from the database.HighProvider keys, optional keys, key-rotation rows, and managed Discord webhook tokens are encrypted with PostgreSQL pgcrypto and key versions.src/utils/security/crypto.ts, src/utils/security/keyManager.ts, src/utils/db/managedWebhookDb.ts, src/db/schema.sqlA DB dump plus the active encryption secret can decrypt stored secrets. Rotate credentials after suspected host or secret compromise.
Repudiation / TamperingA user claims they did not create, edit, or delete memory/configuration.MediumSlash commands are Discord-authenticated, and logging includes command/user/server metadata in many paths.src/commands/*, src/utils/misc/logger.tsLogging is operational, not a tamper-proof audit log.
Denial of ServiceLarge memory imports, document memories, vector operations, or message history imports consume DB/CPU.MediumMemory/document limits, quotas, cooldowns, and size checks are applied before writes in most user-facing paths.src/utils/db/memoryLimits.ts, src/utils/security/rateLimiter.ts, src/utils/db/cooldownManager.tsExpensive queries remain possible if future features bypass shared limit helpers.
Tampering / Stale StateCaches continue serving old permissions, config, memories, webhooks, or Matrix links after a write.MediumCache invalidation is implemented near successful write paths for key state.src/utils/cache/*, src/utils/bridges/matrix/*New DB writes must invalidate matching caches only after successful writes.

2. Discord Commands, Permissions, and Webhooks

Section titled “2. Discord Commands, Permissions, and Webhooks”

Discord is both the identity provider and the primary execution surface.

Threat (STRIDE)ScenarioRiskCurrent MitigationImplementation AreaResidual Risk / Assumption
Elevation of PrivilegeA normal user invokes server-management commands to change provider keys, personas, Matrix links, quotas, whitelist/blacklist settings, memory imports, or prompt configuration.HighCommand loader applies ManageGuild to server/config categories, and sensitive commands also check interaction.memberPermissions.src/utils/discord/commandLoader.ts, src/commands/server/*, src/commands/config/*, src/commands/persona/*Discord permissions are the trust boundary. Misconfigured server roles can grant real admin power.
SpoofingA foreign webhook or bot message is treated as TomoriBot/persona output, poisoning reply attribution or causing response loops.HightomoriChat.ts ignores most bot/webhook messages unless they are Tomori-owned, Matrix relay messages, or manually triggered. Webhook-persona matching uses managed webhook state and persona names.src/events/messageCreate/tomoriChat.ts, src/utils/discord/webhookManager.ts, src/utils/db/managedWebhookDb.tsDisplay-name-only ambiguity can still confuse humans; code must keep treating unrecognized webhooks as untrusted.
Information Disclosure / SpoofingManaged Discord webhook token theft lets an attacker post as a persona.HighManaged webhook tokens are encrypted at rest and tied to a channel/guild. The bot reuses or creates managed webhooks instead of asking users to provide tokens.src/utils/discord/webhookManager.ts, src/utils/db/managedWebhookDb.tsIf the decrypted token leaks from host memory/logs, Discord treats it as bearer auth for that webhook until rotated/deleted.
TamperingLLM-driven manage_message pins, edits, or deletes messages unexpectedly.MediumRuntime checks limit edit/delete to direct bot messages or managed persona webhook messages. Pin requires bot ManageMessages. Message refs are opaque ref_N handles in prompt context.src/tools/functionCalls/manageMessageTool.ts, src/utils/text/messageIdMap.tsThe tool executes with bot permissions, not the human user’s Discord permissions. Server admins should keep the feature flag disabled where not wanted.
TamperingLLM-driven create_thread creates unwanted channels of conversation.MediumRuntime requires thread_creation_enabled, bot CreatePublicThreads and SendMessagesInThreads, and target-channel visibility for the invoking member. Target resolution fails closed on ambiguous names and does not create threads inside threads.src/tools/functionCalls/createThreadTool.ts, src/utils/discord/targetResolver.tsThe thread is created with bot permissions. Server admins should disable the feature flag where thread creation should stay manual.
Information Disclosurecross_channel_message peeks into a channel and leaks recent messages back to another channel.HighRuntime requires bot ViewChannel, requires the invoking guild member to have ViewChannel on the target, and dispatch requires bot SendMessages or SendMessagesInThreads. The server cross-channel blocklist blocks configured channels and forum/media parents.src/tools/functionCalls/crossChannelMessageTool.ts, src/commands/server/crosschannel-blocklist.tsThe bot can still expose messages from channels visible to the invoker and bot. Admins should block sensitive channels where cross-channel tool use is unwanted.
Information DisclosureHidden tool notices or fallback details leak private-channel activity into a public thought-log channel.MediumHidden notices are suppressed for private channels and DMs instead of rerouted.src/utils/discord/toolProgressNotice.tsThought-log channels should still be treated as sensitive operational logs.
Denial of ServiceUsers spam interactions, message triggers, edits, webhooks, or Discord API calls to hit rate limits.MediumDiscord.js handles 429s; TomoriBot uses message/command cooldowns, stream locks, queues, quotas, and emergency memory-pressure cooldowns.src/utils/db/messageCooldown.ts, src/utils/db/cooldownManager.ts, src/utils/security/rateLimiter.ts, src/events/rateLimit/rateLimitLogger.tsManageGuild users are exempt from some cooldowns by design. A compromised admin account can still cause spend and rate-limit pressure.

3. LLM, Prompt, Persona, and Tool Execution

Section titled “3. LLM, Prompt, Persona, and Tool Execution”

LLM output is untrusted. The model can be manipulated by users, memories, documents, web pages, tool results, MCP descriptions, and persona prompts.

Threat (STRIDE)ScenarioRiskCurrent MitigationImplementation AreaResidual Risk / Assumption
TamperingPrompt injection or jailbreak causes persona drift, unsafe instructions, or attempts to reveal system/developer prompt content.MediumContext assembly separates structured system/persona/tool/history blocks, and built-in behavior is enforced in TypeScript where possible.src/utils/text/contextBuilder.ts, src/events/messageCreate/tomoriChat.tsPerfect prompt-injection defense is impossible. Treat all generated text and tool calls as hostile until checked by execution code.
Information Disclosure/tool prompt snapshot exposes assembled prompt, memories, messages, media references, or system instructions.HighCommand has its own gate: ManageGuild bypasses, otherwise prompt_snapshot_enabled must allow non-admin access.src/commands/tool/prompt/snapshot.tsEnabling prompt snapshots for non-admins intentionally expands disclosure.
Tampering / Information DisclosureRAG, server memories, personal memories, imported memories, documents, or SillyTavern presets poison future context or leak sensitive content to later generations.HighMemory scopes are separated, personal privacy levels can block personal memory use, server/user limits exist, and management/export/remove commands are scoped.src/utils/db/memoryLimits.ts, src/commands/memory/*, src/commands/personal/privacy.ts, src/utils/text/contextBuilder.tsServer-wide memory is inherently shared. Moderators must remove poisoned or sensitive server memory.
Elevation of PrivilegeUser prompt causes an unauthorized tool call.HighBuilt-in tool availability is filtered before advertisement. Individual tools also perform concrete runtime checks for high-impact operations such as memory, quotas, message management, image/video generation, and cross-channel access.src/tools/toolRegistry.ts, src/tools/functionCalls/*There is not one universal execution-layer RBAC gate for every feature flag; tools must enforce their own critical checks. New tools must fail closed in execute().
Information DisclosureOpaque Discord snowflakes, raw message IDs, or media IDs appear in prompt context and are reused incorrectly.MediumRecent-message targets are exposed as opaque media_N / ref_N handles and resolved back before execution.src/utils/text/messageIdMap.ts, src/tools/toolRegistry.tsSome legacy raw IDs are still accepted at execution time for compatibility.
Denial of Service / Cost ExhaustionLong prompts, recursive requests, tool loops, video/image generation, or repeated retries consume tokens and provider credits.HighMessage fetch limits, media windows, token/context trimming, stream flood guards, cooldowns, and text/image/video quotas.src/utils/security/rateLimiter.ts, src/utils/quota/*, src/events/messageCreate/tomoriChat.ts, src/utils/discord/streamOrchestrator.tsAdmins must configure quotas and feature flags for their risk tolerance.

TomoriBot supports bundled MCP servers, a REST-backed Brave engine (consumed internally by the unified web_search tool’s dispatcher), bundled URL fetching consumed internally by the unified fetch_url dispatcher, optional self-hosted SearXNG and Crawl4AI sidecars, and guild-registered remote MCP servers.

Threat (STRIDE)ScenarioRiskCurrent MitigationImplementation AreaResidual Risk / Assumption
Elevation of PrivilegeA local MCP server runs malicious code on the host.CriticalLocal MCP servers are operator-controlled deployment components. TomoriBot does not sandbox the MCP process itself.src/utils/mcp/mcpManager.ts, src/tools/mcpServers/*Operators must only run trusted local MCP servers under least-privilege OS/container accounts.
Information DisclosureRemote guild MCP URL points at localhost, RFC1918, link-local, metadata IPs, or other internal services.HighRemote URL validation blocks private/reserved/loopback addresses in production, requires HTTPS in production, allows localhost HTTP only for development, and validates before each HTTP transport request.src/utils/mcp/mcpUrlSecurity.ts, src/utils/security/userRemoteFetch.ts, src/utils/mcp/guildMcpManager.tsBun’s undici DNS interceptor support is best effort; validation still runs, but DNS pinning can fall back when unavailable.
TamperingMCP tool descriptions, names, schemas, or results contain prompt injection.HighTool names that collide with built-in or global MCP names are skipped. Tool results are returned through the tool pipeline rather than granted direct DB/filesystem access.src/tools/toolRegistry.ts, src/utils/mcp/guildMcpManager.ts, src/utils/mcp/mcpExecutor.tsAdmin-registered MCP tools are trusted. A malicious MCP can still manipulate model behavior through text output.
Elevation of PrivilegeDangerous MCP tool such as shell execution or broad file access is registered and the LLM calls it.CriticalTomoriBot only passes arguments to registered MCP tools; it does not provide host filesystem or shell access by itself.src/utils/mcp/*Security depends on MCP server design and admin trust. Do not expose dangerous MCP tools to guilds.
Information Disclosure / SSRFWeb fetch/search tools retrieve attacker-controlled pages, huge responses, internal URLs, or pages containing data-exfiltration prompts.Medium / HighFetch size checks, max content truncation, progress notices, feature flags, FETCH_URL_ALLOW_PRIVATE_NETWORK=false private-target blocking before fetch_url dispatch, and SSRF-protected remote fetch paths for guild MCP HTTP transports.src/tools/fetchUrl/*, src/utils/mcp/mcpExecutor.ts, src/tools/mcpServers/fetch/fetchHandler.ts, src/tools/restAPIs/brave/*Search/fetch output is untrusted prompt content. Built-in Brave result image fetches and third-party search APIs should be treated as external content.
Elevation of Privilege / Information DisclosureA compromised SearXNG sidecar image makes outbound calls under the task’s network/IAM identity or attempts to read other co-located container state.HighSidecar receives only SEARXNG_SECRET from Secrets Manager — never the combined tomoribot/production secret. GCP Terraform disables the sidecar by default. Image is intended to be pinned by sha256 digest when enabled (see servers/searxng/README.md upgrade procedure).terraform/aws/ecs-health-check.tf, terraform/gcp/cloud-run.tf, servers/searxng/README.mdDefaults in docker-compose.yaml and the optional sidecar image variable use searxng/searxng:latest. Production deployments that enable SearXNG must override with a pinned digest before merge, otherwise an upstream image rotation can auto-deploy on the next task restart.
Information Disclosure / Open Proxy AbuseThe SearXNG sidecar is exposed beyond the private container network (e.g. added to Cloud Run public ingress or a public ALB), turning it into an open metasearch proxy.Highservers/searxng/limiter.toml disables bot detection on the assumption that only TomoriBot on the private network talks to the sidecar. Deployment configs bind SearXNG to loopback (http://localhost:8080/) inside the task / pod and never publish port 8080.servers/searxng/limiter.toml, docker-compose.yaml, terraform/aws/ecs-health-check.tf, terraform/gcp/cloud-run.tfIf operators expose port 8080 publicly, anonymous internet traffic can use the instance to scrape Google/Bing/Brave on the operator’s behalf. Never add SearXNG to public ingress. Never expose SEARXNG_BASE_URL as a per-guild slash-command setting — that would make it a user-controlled URL and require fetchUserRemoteUrl().
Information Disclosure / SSRF / Open Proxy AbuseThe Crawl4AI sidecar is exposed publicly or allowed to fetch internal-only URLs with the bot’s network position.HighCrawl4AI is opt-in via CRAWL4AI_BASE_URL, hidden behind fetch_url, and should run only on a private compose/task network. TomoriBot health-checks the sidecar, blocks private/internal target URLs before dispatch unless FETCH_URL_ALLOW_PRIVATE_NETWORK=true, and falls back to mcp_fetch when unavailable.src/tools/fetchUrl/crawl4aiEngine.ts, src/tools/restAPIs/crawl4ai/*, docker-compose.yaml, servers/crawl4ai/README.mdBrowser-rendered fetch output is untrusted prompt content. Operators must keep port 11235 private, pin the image for production, and avoid exposing CRAWL4AI_BASE_URL as a per-guild/user setting.

5. Custom Provider, Endpoint, Speech, and Transcription Surfaces

Section titled “5. Custom Provider, Endpoint, Speech, and Transcription Surfaces”

Custom endpoints include text, embedding, image, video, speech/TTS, and transcription/STT capabilities. Server-scoped endpoints are admin configured. Personal endpoints are user scoped and use stricter URL policy.

Threat (STRIDE)ScenarioRiskCurrent MitigationImplementation AreaResidual Risk / Assumption
Information Disclosure / SSRFCustom endpoint URL targets internal infrastructure or changes DNS after validation.HighRegistration uses validateRemoteMcpUrl(). Runtime custom endpoint calls use fetchUserRemoteUrl(), which revalidates redirects and resolves target hosts before sending. Personal endpoints pass strict: true.src/commands/config/custom-endpoint/*, src/commands/personal/custom-endpoint/*, src/providers/custom/*, src/utils/security/userRemoteFetch.tsServer endpoints can use localhost in non-production for local development. Production must keep RUN_ENV=production.
Information DisclosureProvider request sends chat history, images, audio, voice samples, or memories to an attacker-controlled custom endpoint.HighEndpoint registration is explicit and admin/user scoped. Credentials are attached only for that configured endpoint/provider.src/utils/provider/credentialResolver.ts, src/utils/provider/customEndpointService.ts, src/providers/custom/*This is inherent BYO endpoint behavior. Endpoint owners can see request payloads sent to them.
Information DisclosureSpeech/TTS clone endpoint receives a stored voice sample and generated script.HighSpeech endpoints are server-scoped admin configuration. Voice sample storage is explicit, and TTS requires an assigned persona voice.src/providers/custom/styles/ttsCloningAdapter.ts, src/utils/storage/voiceSampleStorage.ts, src/tools/functionCalls/generateVoiceMessageTool.tsVoice samples are biometric-like data. Treat speech endpoints and storage buckets as sensitive.
Information DisclosureTranscription endpoint receives user-uploaded audio from Discord messages.HighSTT only runs when a transcription endpoint is configured. Audio download uses size and timeout checks.src/utils/audio/audioAttachmentTranscription.ts, src/providers/custom/styles/transcriptionOpenAIAdapter.tsUsers in enabled servers should expect audio attachments may be transcribed and sent to the configured STT endpoint.
Information Disclosure / SSRFRuntime speech/transcription adapters use a stored endpoint URL that has changed DNS since registration.HighRuntime TTS and STT calls use fetchUserRemoteUrl() for the configured endpoint URL, so DNS validation and redirect handling are repeated before sending audio or voice-sample payloads.src/providers/custom/styles/ttsCloningAdapter.ts, src/providers/custom/styles/transcriptionOpenAIAdapter.ts, src/utils/security/userRemoteFetch.tsServer endpoints remain admin-controlled and can intentionally send audio to the configured service. Production must keep RUN_ENV=production for strict server-endpoint SSRF policy.
Tampering / DoSComfyUI or custom image/video workflow JSON is malicious, huge, or unexpectedly expensive.MediumWorkflow JSON is provided during endpoint setup and stored in endpoint config. Generation is gated by image/video feature flags and quotas.src/commands/config/custom-endpoint/add.ts, src/providers/custom/customEndpointDispatcher.ts, src/utils/quota/*The remote workflow runtime is outside TomoriBot’s sandbox. Endpoint operators own that risk.

6. File, Attachment, Media, and Asset Processing

Section titled “6. File, Attachment, Media, and Asset Processing”

TomoriBot processes Discord attachments, images, videos, GIFs, PDFs/text files, audio, avatars, character references, and Matrix media.

Threat (STRIDE)ScenarioRiskCurrent MitigationImplementation AreaResidual Risk / Assumption
Denial of ServiceOversized or slow Discord attachment downloads exhaust memory or worker time.HighsafeDownload() pre-checks known size, validates the target URL through fetchUserRemoteUrl(), enforces content-length and final size checks, and uses timeouts. User-uploaded workflow/config imports, media-context images, GIFs, avatars, character references, and provider-returned media downloads use the shared wrapper.src/utils/security/safeDownload.ts, src/utils/documents/textExtractor.ts, src/utils/audio/audioAttachmentTranscription.ts, src/utils/teach/batchUploadUtils.ts, src/utils/image/*Fixed first-party provider API calls still use direct fetch().
Denial of ServiceMalicious PDF or text file stalls pdf-parse, string normalization, or the single-threaded runtime.HighFile size limit, known-binary extension/MIME blocklist, memory-pressure guard, text length truncation.src/tools/functionCalls/readFileTool.ts, src/utils/documents/textExtractor.ts, src/utils/security/rateLimiter.tsA crafted file under the size cap can still stress parsers. Process supervision remains important.
Information Disclosureread_file, image analysis, GIF processing, or media-context expansion exposes attachments from recent messages.MediumTools use recent-message windows and opaque media_N handles.src/tools/functionCalls/readFileTool.ts, src/tools/functionCalls/analyzeImageTool.ts, src/tools/functionCalls/processGifTool.ts, src/tools/functionCalls/increaseMediaContextTool.tsThese tools operate with bot channel visibility. Sensitive attachments in channels visible to the bot may be sent to the configured model/provider.
Information Disclosure / SSRFAvatar or character-reference storage loads arbitrary remote URLs.MediumUser upload paths go through safe download; local stored paths are constrained under data/avatars, data/charreferences, and data/voice-samples; remote character references are reloaded with safeDownload()/fetchUserRemoteUrl() URL validation.src/utils/storage/avatarStorage.ts, src/utils/storage/charrefStorage.ts, src/utils/storage/voiceSampleStorage.tsStored remote assets should still be limited to Tomori-controlled S3/CloudFront or Discord CDN where possible.
Tampering / Information DisclosureImage/video generation or analysis sends user images, avatars, stickers, emoji, or embeds to model providers.Medium / HighFeature flags, provider capability checks, quota checks, and prompt-visible progress notices.src/tools/functionCalls/generateImageTool.ts, src/tools/functionCalls/generateImageNaiTool.ts, src/tools/functionCalls/generateVideoTool.ts, src/utils/image/*Provider privacy guarantees are outside TomoriBot. Users should not upload sensitive media into model-enabled channels.

The Matrix bridge is optional and runs as a Matrix appservice. It relays Matrix messages into Discord through webhooks and relays TomoriBot responses back to Matrix through virtual persona users.

Threat (STRIDE)ScenarioRiskCurrent MitigationImplementation AreaResidual Risk / Assumption
Spoofing / Elevation of PrivilegeUnauthorized callers post Matrix appservice transactions to TomoriBot.Criticalmatrix-appservice-bridge registration uses MATRIX_HS_TOKEN for homeserver-to-appservice authentication. Public callback URL must be HTTPS unless localhost.src/utils/bridges/matrix/events.tsDeployment must not expose the appservice listener without the homeserver auth path. Keep MATRIX_HS_TOKEN secret.
Information DisclosureA Matrix room is linked to a sensitive Discord channel by mistake.High/server matrix link requires ManageGuild, checks room encryption state, and stores explicit room-channel links.src/commands/server/matrix/link.ts, src/utils/bridges/matrix/rooms.tsOnce linked, Matrix room members can interact with the Discord channel through the bridge. Room membership is controlled on the Matrix side.
Information DisclosureE2EE Matrix rooms are linked, causing unreadable or misleading bridge behavior.MediumLink command checks for m.room.encryption and blocks encrypted rooms.src/utils/bridges/matrix/rooms.ts, src/commands/server/matrix/link.tsIf the encryption check fails, code proceeds optimistically per comments; operators should keep linked rooms unencrypted.
SpoofingRemote Matrix users choose names resembling personas or Discord users.MediumDiscord webhook username includes `[Matrix@user:server] localpart`; bridge user IDs are tracked in context. Virtual persona loop prevention checks the configured homeserver suffix.src/utils/bridges/*, src/utils/bridges/matrix/*, src/events/messageCreate/tomoriChat.ts
Denial of ServiceMatrix media events relay large files into Discord or exhaust memory.MediumMedia relay enforces MATRIX_MAX_ATTACHMENT_MB, timeout, content-length, and final buffer size checks.src/utils/bridges/matrix/matrixManager.ts, src/events/messageCreate/matrixRelay.tsFiles are proxied through the configured homeserver using appservice auth. A hostile homeserver can still pressure the bridge within configured limits.
Tampering / DoSAny Matrix user in a linked room issues /kill or /refresh.MediumCommands are limited to linked Matrix rooms and affect only the linked Discord channel.src/utils/bridges/matrix/events.tsThese Matrix text commands are not Discord-permission-gated. Matrix room moderation is the control.

Threat (STRIDE)ScenarioRiskCurrent MitigationImplementation AreaResidual Risk / Assumption
Tampering / Elevation of PrivilegeMalicious dependency update runs code during install/build/runtime.Highbun.lock, dependency pinning/overrides, patches, CI audit, and container scanning guidance.package.json, bun.lock, patches/, .github/workflows/*, DockerfileUpstream registry or maintainer compromise remains possible. Review lockfile diffs carefully.
Information DisclosureCI/CD secrets leak through logs or compromised actions.HighProduction deployment uses OIDC where documented and avoids long-lived static AWS credentials where possible..github/workflows/*, docs/subsystems/security.mdGitHub Actions and cloud IAM configuration remain part of the trust boundary.
Information Disclosure / TamperingProduction secrets are loaded from the wrong source or missing key versions break decryption.HighProduction uses AWS Secrets Manager; startup validates required secrets and initializes key manager after loading. Versioned encryption keys support rotation.src/utils/security/secretsManager.ts, src/index.ts, src/utils/security/keyManager.tsRUN_ENV must be set correctly. Removing old key versions before rotation completes can make rows undecryptable.
Denial of ServiceRuntime memory leak, parser crash, provider hang, or unhandled promise crashes the process.MediumMemory monitor/guardrails, provider timeouts in several adapters, stream error handling, and operational process restart expectations.src/timers/memoryMonitor.ts, src/utils/security/rateLimiter.ts, provider adaptersExternal process supervision is still required for production reliability.

These are actionable hardening items from the residual-risk column. Keep this section focused on concrete work, not general advice.

AreaIssueSuggested Action
Tool executionCritical runtime checks are implemented by individual tools rather than a single universal final gate.Standardize fail-closed checks for feature flags, quota source, Discord permissions, target ownership, and target visibility in shared helpers, then audit every built-in tool against them.
AreaAction
MCPDocument that shell, file, database, or broad-network MCP servers are equivalent to granting host or internal-network access.
MatrixDocument production appservice exposure requirements, token rotation expectations, and room moderation requirements for /kill and /refresh.
SecretsDocument the rotation procedure after provider key, webhook token, Matrix token, or host compromise.
Discord permissionsRecommend least-privilege bot channel access and call out that several tools operate with bot visibility.
Quotas and feature flagsRecommend conservative defaults for image, video, cross-channel, web fetch, prompt snapshot, and manage-message features.

  1. Enforce security in TypeScript, not only in prompts.
  2. Use fetchUserRemoteUrl() for user-supplied or admin-configured remote endpoints unless the URL is a fixed first-party provider URL.
  3. Use safeDownload() or equivalent size/timeout/final-size checks for user-controlled media.
  4. Use Bun SQL template literals for values and sqlSecurity.ts helpers for dynamic columns.
  5. Scope all DB reads/writes by server/user/persona/channel as appropriate.
  6. Invalidate caches after successful writes, in the same code path.
  7. New tools must perform critical feature-flag, permission, quota, and target-ownership checks inside execute(), even if they are filtered before advertisement.
  8. Treat MCP definitions, MCP results, web pages, documents, memories, imports, and custom endpoint responses as untrusted prompt content.