Each engagement gets its own SQLite database with encrypted sensitive fields.
Per-Engagement Isolation#
TantoC2 uses a separate SQLite database for each engagement:
| |
This provides complete data isolation between engagements — agents, tasks, credentials, and audit entries for one engagement are invisible to another.
Central Database#
The central database (central.db) stores cross-engagement data:
| Table | Purpose |
|---|---|
operators | User accounts, roles, password hashes |
engagements | Engagement metadata, status, encrypted master keys |
engagement_access | Operator-to-engagement access grants |
Engagement Database Schema#
Each engagement database contains:
| Table | Purpose |
|---|---|
agents | Registered agents with metadata, relay info, crypto session state |
tasks | Task queue (pending, sent, running, completed, failed, expired) |
task_results | Task result data (supports multiple results per task for streaming) |
archived_tasks | Archived completed tasks |
archived_task_results | Archived task results |
credentials | Credential store with encrypted secrets |
builds | Agent build records |
loaded_modules | Modules loaded in agents (managed mode tracking) |
p2p_links | P2P relay links between agents (active, degraded, broken, replaced) |
file_transfers | File transfer records with SHA-256 hash verification |
agentless_executions | Tools module execution records |
agentless_execution_results | Per-target execution results |
proxy_configs | Proxy configurations (SOCKS4, SOCKS5, SSH tunnel) |
collection_requests | Collector file download requests (pending, approved, denied) |
audit_log | All operator actions with timestamps |
In-memory state (not persisted to DB): Listeners are managed in-memory by
ListenerManager. Collector grants are stored in-memory in RBACService. Both are lost on server restart.Key Agent Fields#
| Field | Description |
|---|---|
agent_package_type | Which agent package registered this agent |
session_token | 16-byte session identifier |
crypto_session_data | JSON-encoded crypto session state (keys, counters) |
relay_agent_id | Agent through which this agent relays traffic (P2P) |
relay_port | Port the relay agent listens on |
parent_agent_id | Parent agent (for daemonized module spawns) |
mode | beacon or session |
status | active, dormant, dead, killed |
Encrypted Fields#
Sensitive fields are encrypted with the engagement’s master key (AES-256-GCM):
credentials.secret_encrypted— credential secrets
Schema Migrations#
The database schema evolves forward with each phase. SQLAlchemy manages migrations:
- Migrations run automatically when an engagement is activated
- A pre-migration backup is created before any schema changes
- When importing archived engagements, migrations are applied automatically
Task Archival#
Completed tasks older than task_archival_age (default: 24 hours) are moved from tasks to archived_tasks. This keeps the active task list small while preserving history.
Archived tasks remain queryable via:
| |
Backup#
File-Level Backup#
| |
Encrypted Archival#
Use the engagement archive API for portable, encrypted backups:
| |