Skip to main content
  1. Documentation/
  2. Architecture/

Database

Table of Contents
Each engagement gets its own SQLite database with encrypted sensitive fields.

Per-Engagement Isolation
#

TantoC2 uses a separate SQLite database for each engagement:

1
2
3
4
5
6
data/
  engagements/
    <engagement-1-id>.db
    <engagement-2-id>.db
    ...
  central.db    # Operators, engagements metadata, system config

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:

TablePurpose
operatorsUser accounts, roles, password hashes
engagementsEngagement metadata, status, encrypted master keys
engagement_accessOperator-to-engagement access grants

Engagement Database Schema
#

Each engagement database contains:

TablePurpose
agentsRegistered agents with metadata, relay info, crypto session state
tasksTask queue (pending, sent, running, completed, failed, expired)
task_resultsTask result data (supports multiple results per task for streaming)
archived_tasksArchived completed tasks
archived_task_resultsArchived task results
credentialsCredential store with encrypted secrets
buildsAgent build records
loaded_modulesModules loaded in agents (managed mode tracking)
p2p_linksP2P relay links between agents (active, degraded, broken, replaced)
file_transfersFile transfer records with SHA-256 hash verification
agentless_executionsTools module execution records
agentless_execution_resultsPer-target execution results
proxy_configsProxy configurations (SOCKS4, SOCKS5, SSH tunnel)
collection_requestsCollector file download requests (pending, approved, denied)
audit_logAll 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
#

FieldDescription
agent_package_typeWhich agent package registered this agent
session_token16-byte session identifier
crypto_session_dataJSON-encoded crypto session state (keys, counters)
relay_agent_idAgent through which this agent relays traffic (P2P)
relay_portPort the relay agent listens on
parent_agent_idParent agent (for daemonized module spawns)
modebeacon or session
statusactive, 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:

1
2
GET /api/v1/tasks/archived?engagement_id=<id>
GET /api/v1/tasks/archived/<task_id>?engagement_id=<id>

Backup
#

File-Level Backup
#

1
cp -r /opt/tantoc2/data /opt/tantoc2/data.backup.$(date +%Y%m%d)

Encrypted Archival
#

Use the engagement archive API for portable, encrypted backups:

1
2
POST /api/v1/engagements/<id>/archive
{"passphrase": "...", "output_path": "/path/to/archive"}