Skip to content

Threat Model

This document provides a STRIDE-based threat analysis of dbward’s architecture.

AssetLocationSensitivity
Database credentialsAgent config/env varsCritical — full DB access
Ed25519 signing keyServer filesystem (signing.key)Critical — token forgery
API token hashesServer SQLiteHigh — authentication
Approval state & workflowsServer SQLiteHigh — authorization logic
Audit log (hash chain)Server SQLiteHigh — accountability
Query textServer SQLite (requests table)Medium — may contain secrets
Query resultsAgent → result storeMedium — business data
OIDC configurationServer configMedium — auth infrastructure
ActorTrust LevelCapabilities
Authenticated user (CLI/MCP)Partial — authenticated, role-limitedCreate requests, view own results
AI agent (MCP client)Partial — same as user, no special privilegesPropose operations via MCP tools
ApproverPartial — authenticated, approve-roleApprove/reject requests
dbward-agentHigh — holds DB credentialsExecute approved operations
ServerHigh — issues execution tokensManage state, verify auth, sign tokens
External attackerNoneNetwork access only
Malicious insiderPartial — valid credentialsAbuse legitimate access
┌─ Boundary 1: Network ──────────────────────────────────────────────┐
│ │
│ ┌─ Boundary 2: Server Process ─────────────────────────────────┐ │
│ │ Auth middleware, RBAC, workflow engine, token signer │ │
│ │ SQLite state (audit, approvals, tokens) │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Boundary 3: Agent Process ──────────────────────────────────┐ │
│ │ Token verifier, capability checker, DB driver │ │
│ │ DB credentials (env vars / config) │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Boundary 4: External Services ──────────────────────────────┐ │
│ │ Target databases, OIDC IdP, Slack API │ │
│ └───────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
ThreatRiskMitigation
Forged API tokenHighSHA-256 hash verification, prefix-based lookup, expiry check
Spoofed OIDC JWTHighJWKS-based RS256 signature verification, issuer/audience validation
Fake agent registrationHighAgent token required, capability config limits scope
Spoofed Slack interactionMediumHMAC-SHA256 signature verification (constant-time), timestamp ±5min
ThreatRiskMitigation
Execution token modificationCriticalEd25519 signature + SHA-256 content hash binding
Audit log manipulationHighHash chain — each entry includes hash of previous entry
SQLite database file tamperingMediumPRAGMA foreign_keys, application-level integrity checks
Webhook payload tamperingMediumHMAC-SHA256 signature in X-Dbward-Signature header
ThreatRiskMitigation
Denying approval actionHighHash-chain audit with actor_id, timestamp, matched_selector
Denying executionHighExecution record with agent_id, token, start/end timestamps
Denying request creationMediumAudit event at creation with requester identity

Audit verification model: Run verify_chain() periodically (recommended: daily cron). Each event’s hash is recomputed from its fields + previous hash. Any mismatch indicates tampering. Checkpoints can be exported to external storage for independent verification.

ThreatRiskMitigation
DB credential leakageCriticalAgent-only isolation — creds never sent to server or CLI
Query text exposure via webhookMediumSQL literals redacted to ?; parse failure → SHA-256 only
API token exposureMediumOnly SHA-256 hash stored; prefix for lookup only
OIDC token in logsLowTokens not logged; only subject_id extracted
ThreatRiskMitigation
JWKS endpoint floodingMediumCache with 1h TTL; refresh only on signature mismatch (not claim errors)
Approval queue floodingLowRate limiting at reverse proxy; request size limit 100KB
SQLite write contentionMediumbusy_timeout=10s, IMMEDIATE transactions for critical paths
Agent starvationLowMultiple agents supported; poll interval configurable
ThreatRiskMitigation
Self-approvalHighConfigurable prohibition (default: denied); checked in approve path
Break-glass abuseMediumRequires explicit flag + mandatory reason; audit-logged; role-restricted
Role escalation via OIDC groupsMediumServer-side group→role mapping; no client-side role claims
AI proposal launderingMediumSQL Review (10 rules); content-bound execution token; human must approve exact SQL
ThreatDescriptionMitigation
Prompt injection via schemaMalicious table/column names influence AI proposalsSQL Review catches destructive patterns; human approves final SQL
Proposal launderingAI explanation appears safe but SQL is harmfulExecution token bound to exact SQL text; approver sees actual SQL
Multi-step decompositionBreaking a dangerous operation into individually-safe stepsWorkflow can require approval per-request; audit shows full sequence
Human over-trustApprover rubber-stamps AI proposalsMulti-step approval; different approvers per step; risk scoring in context
ScenarioBehaviorRecovery
Server crash during executionAgent detects heartbeat response failureAgent marks job failed; on server restart, request can be re-dispatched via resume
OIDC IdP unavailableAll OIDC auth fails (fail-closed)API token auth still works; IdP recovery restores OIDC
Agent loses DB connectionExecution fails with errorResult reported as failed; can be retried after resume
Signing key unavailableToken issuance failsNo new executions possible; existing in-flight tokens still valid until expiry
Clock drift >5minSlack signatures rejected; token expiry unreliableNTP sync required; operations resume after clock correction
LimitationImpactPlanned Mitigation
SQLite not encrypted at restFile access = full state accessFilesystem permissions (0700); encrypted storage planned
Single-instance serverNo HA; restart = in-memory result lossSufficient for <100 concurrent users; HA planned for v0.2+
File-based signing keyNo HSM/KMS protectionRotation via restart; KMS integration planned
No SBOM or image signingSupply chain verification limitedcargo-deny for advisories; image signing planned
InMemory result channelServer restart loses pending resultsTTL=10min; clients can re-poll after restart