Skip to the content.

Configuration reference

Every runtime knob lives in an env var read by orchestrator/config.py. Nothing is hard-coded. Services refuse to start if any required=True variable is unset.

Canonical source: orchestrator/config.py.

Core

Variable Default Required Purpose
DATABASE_URL Postgres DSN for the orchestrator
CELERY_BROKER_URL redis://localhost:6379/0   Celery broker
CELERY_RESULT_BACKEND redis://localhost:6379/1   Celery results backend
ANALYSIS_NETWORK_CIDR 192.168.100.0/24   Analysis-bridge CIDR (used for IOC classification)
QUARANTINE_ROOT /srv/sandgnat/quarantine   Where dropped files are moved after ingestion
ARTIFACT_STAGING_ROOT /srv/sandgnat/staging   SMB/NFS staging share root
ANALYSIS_DEFAULT_TIMEOUT 300   Detonation timeout in seconds
MAX_CONCURRENT_ANALYSES 4   Upper bound for the Postgres pool sizing

Proxmox

Variable Default Required Purpose
PROXMOX_HOST Proxmox API host
PROXMOX_USER root@pam   API user
PROXMOX_TOKEN_NAME API token name
PROXMOX_TOKEN_VALUE API token value
PROXMOX_VERIFY_SSL true   TLS verification
PROXMOX_NODE Proxmox node to place VMs on
PROXMOX_TEMPLATE_VMID 9000   Windows template vmid
PROXMOX_CLEAN_SNAPSHOT clean   Template snapshot to linked-clone from
PROXMOX_CLONE_BOOT_TIMEOUT_SECONDS 120   Max wait for a fresh clone to reach running

Windows VM pool

Variable Default Purpose
VM_POOL_VMID_MIN 9100 First vmid in Windows pool range
VM_POOL_VMID_MAX 9199 Last vmid in Windows pool range
VM_POOL_STALE_LEASE_SECONDS 1800 Reap leases older than this

Linux VM pool (static-analysis stage)

Variable Default Purpose
LINUX_VM_POOL_VMID_MIN 9200 First vmid in Linux pool range
LINUX_VM_POOL_VMID_MAX 9299 Last vmid in Linux pool range
LINUX_TEMPLATE_VMID 9001 Linux template vmid
LINUX_CLEAN_SNAPSHOT clean Linux template snapshot name
LINUX_VM_POOL_STALE_LEASE_SECONDS 600 Reap stale Linux leases

Static analysis

Variable Default Purpose
STATIC_ANALYSIS_ENABLED false Route intake through the static stage first
STATIC_SHORT_CIRCUIT_THRESHOLD 0.85 Jaccard threshold for near-duplicate skip
STATIC_SHORT_CIRCUIT_FLAVOUR either byte / opcode / either
STATIC_ANALYSIS_TIMEOUT 240 Static-stage timeout in seconds
STATIC_YARA_DEEP_RULES_DIR "" Directory of .yar files for the deep scan

Intake HTTP service

Variable Default Required Purpose
INTAKE_API_KEY ✅ (to start service) Shared secret for X-API-Key header
INTAKE_BIND_HOST 127.0.0.1   Flask bind address
INTAKE_BIND_PORT 8080   Flask bind port
INTAKE_MAX_SAMPLE_BYTES 134217728 (128 MiB)   Hard upload-size cap
INTAKE_MIN_SAMPLE_BYTES 16   Reject anything smaller
INTAKE_YARA_RULES_DIR ""   Directory of intake-time YARA rules
VIRUSTOTAL_API_KEY ""   If set, enable VT hash lookup
VIRUSTOTAL_BASE_URL https://www.virustotal.com/api/v3   VT v3 base URL
VIRUSTOTAL_TIMEOUT_SECONDS 10   VT request timeout

Linux guest agent

Set these on the Linux static-analysis guest, not on the orchestrator.

Variable Default Purpose
LINUX_GUEST_STAGING_ROOT /srv/sandgnat/staging Where the SMB share is mounted
LINUX_GUEST_POLL_INTERVAL 2.0 Watcher poll interval, seconds
LINUX_GUEST_CAPA_EXE capa Path to the CAPA binary
LINUX_GUEST_YARA_DEEP_RULES_DIR "" Deep YARA rules on the guest
LINUX_GUEST_MAX_STRINGS_BYTES 1048576 Cap on strings kept in envelope

Windows guest agent (anti-analysis mitigations)

Set these on the Windows detonation guest. All are opt-out — defaults match the hardened template produced by the Phase A–C template-bake runbook. Env vars take precedence over the defaults in guest_agent/config.py, so non-hardened dev VMs can disable individual mitigations without rebuilding the frozen agent.

Paths (Phase C)

Variable Default Purpose
SANDGNAT_DECOY_USER value of USERNAME, else Default Username whose AppData holds the workspace (read literally, not %-expanded)
SANDGNAT_WORK_ROOT C:\Users\<decoy>\AppData\Local\Microsoft\PowerManagement Per-job workspace root on the guest
SANDGNAT_STAGING_ROOT \\192.168.100.1\analysis UNC path to the orchestrator staging share (no drive letter)
SANDGNAT_PROCMON C:\Windows\System32\SystemAudit.exe Renamed ProcMon binary

Capture tools (Phase C)

Point these at the tool binaries and NIC on your template. If Wireshark or Regshot live elsewhere, or the capture NIC isn’t named Ethernet, capture silently fails without these overrides.

Variable Default Purpose
SANDGNAT_TSHARK C:\Program Files\Wireshark\tshark.exe tshark binary for PCAP capture
SANDGNAT_REGSHOT C:\Tools\Regshot\Regshot-x64-Unicode.exe Regshot binary for the registry before/after diff
SANDGNAT_CAPTURE_INTERFACE Ethernet NIC name tshark captures on
SANDGNAT_POLL_INTERVAL 2.0 Seconds between staging-share polls in the watcher

Activity simulator (Phase D)

Set SANDGNAT_ACTIVITY_ENABLED=0 to disable the entire simulator; the individual toggles only apply when the master switch is on.

Variable Default Purpose
SANDGNAT_ACTIVITY_ENABLED 1 Master on/off for the four simulator threads
SANDGNAT_ACTIVITY_WARMUP 30 Seconds to wait after sample launch before activity fires
SANDGNAT_ACTIVITY_MOUSE_JIGGLE 1 Enable the mouse-jiggle loop
SANDGNAT_MOUSE_JIGGLE_MIN 20 Min interval between jiggles (seconds)
SANDGNAT_MOUSE_JIGGLE_MAX 60 Max interval between jiggles (seconds)
SANDGNAT_ACTIVITY_CURSOR_TOUR 1 Enable the cursor-tour loop
SANDGNAT_CURSOR_TOUR_MIN 180 Min interval between tours (seconds)
SANDGNAT_CURSOR_TOUR_MAX 420 Max interval between tours (seconds)
SANDGNAT_ACTIVITY_KEYBOARD_NOISE 1 Enable the hidden-Notepad typing loop
SANDGNAT_KEYBOARD_NOISE_MIN 240 Min interval (seconds)
SANDGNAT_KEYBOARD_NOISE_MAX 600 Max interval (seconds)
SANDGNAT_ACTIVITY_WINDOW_DANCE 1 Enable the open/close app loop
SANDGNAT_WINDOW_DANCE_MIN 120 Min interval (seconds)
SANDGNAT_WINDOW_DANCE_MAX 300 Max interval (seconds)

Sleep patcher (Phase E)

Variable Default Purpose
SANDGNAT_SLEEP_PATCHER_DLL <agent_dir>/sleep_patcher.dll Absolute path to sleep_patcher.dll; falls back to the agent directory
SANDGNAT_SLEEP_PATCH_LOG <workspace>/sleep_patches.jsonl Set automatically by the runner per-job; DLL writes here

If the DLL is missing the runner continues without injection (Phase G still catches the import pattern). Off-Windows the injector refuses cleanly; tests can force the Windows code path with SANDGNAT_FAKE_WIN32=1.

Security posture

Examples

Minimal orchestrator .env

DATABASE_URL=postgresql://sandgnat:***@pg.internal:5432/sandgnat
CELERY_BROKER_URL=redis://redis.internal:6379/0
PROXMOX_HOST=proxmox.internal
PROXMOX_TOKEN_NAME=sandgnat
PROXMOX_TOKEN_VALUE=***
PROXMOX_NODE=pve1

INTAKE_API_KEY=some-long-opaque-string
QUARANTINE_ROOT=/srv/sandgnat/quarantine
ARTIFACT_STAGING_ROOT=/srv/sandgnat/staging

Enable the static pre-stage

STATIC_ANALYSIS_ENABLED=1
STATIC_SHORT_CIRCUIT_THRESHOLD=0.85
STATIC_YARA_DEEP_RULES_DIR=/etc/sandgnat/yara-deep
LINUX_TEMPLATE_VMID=9001

Enable VT pre-check

VIRUSTOTAL_API_KEY=xxxxxxxx...

Dev / local stack

DATABASE_URL=postgresql://postgres:postgres@localhost:5432/sandgnat
CELERY_BROKER_URL=redis://localhost:6379/0
INTAKE_API_KEY=dev-key-not-for-production
QUARANTINE_ROOT=/tmp/sandgnat/quarantine
ARTIFACT_STAGING_ROOT=/tmp/sandgnat/staging
# Proxmox vars still required to import the module; use placeholders:
PROXMOX_HOST=localhost
PROXMOX_TOKEN_NAME=dev
PROXMOX_TOKEN_VALUE=dev
PROXMOX_NODE=dev

See tutorials/02-local-dev-stack.md for the full dev setup.