Problem
Config files delivered to field devices have no verifiable provenance — a forensic examiner cannot determine which specific config, from which specific server instance, was delivered to a compromised device.
Solution — Steganographic Config Watermarking
Each delivered config receives a unique, verifiable HMAC-SHA384 watermark embedded in a non-operational field. The server can identify any config retrieved from a captured device.
Watermark Construction
# services/watermark.py
def apply_watermark(config: dict, machine_id: str, ek_fingerprint: str, nonce: str) -> dict:
watermark = hmac_sha384(
key=settings.watermark_secret,
msg=f"{machine_id}:{ek_fingerprint}:{nonce}:{utcnow_iso()}"
)
config["_itl_wm"] = watermark[:32] # 256-bit prefix, not full hash
return config
Registry
# models/watermark.py
class WatermarkRegistry(Base):
id: uuid
machine_id: uuid
ek_fingerprint: str
watermark_prefix: str # stored — the 32-char prefix embedded in config
delivery_nonce: str
delivered_at: datetime
config_hash: str # SHA-384 of the plaintext config before encryption
Identification
POST /api/v1/forensics/watermark/identify
Authorization: Bearer <forensic_admin>
{ "watermark_fragment": "base64-fragment-from-captured-config" }
Server brute-forces the registry for matching prefix → returns machine identity, delivery time, operator.
Key Rotation
ITL_WATERMARK_SECRET rotated quarterly. Old registry entries remain verifiable against their archived key version.
MITRE ATT&CK
- T1005 — Data from Local System (source tracing)
- T1041 — Exfiltration Over C2 Channel (watermark identifies leak source)
Files
- New:
services/watermark.py
- New:
models/watermark.py
- New:
routers/forensics.py — POST /forensics/watermark/identify
- Extend:
handlers/config_delivery.py — apply watermark on every delivery
- New env var:
ITL_WATERMARK_SECRET, ITL_WATERMARK_KEY_VERSION
- Alembic migration:
add_watermark_registry_table
Acceptance Criteria
Problem
Config files delivered to field devices have no verifiable provenance — a forensic examiner cannot determine which specific config, from which specific server instance, was delivered to a compromised device.
Solution — Steganographic Config Watermarking
Each delivered config receives a unique, verifiable HMAC-SHA384 watermark embedded in a non-operational field. The server can identify any config retrieved from a captured device.
Watermark Construction
Registry
Identification
Server brute-forces the registry for matching prefix → returns machine identity, delivery time, operator.
Key Rotation
ITL_WATERMARK_SECRETrotated quarterly. Old registry entries remain verifiable against their archived key version.MITRE ATT&CK
Files
services/watermark.pymodels/watermark.pyrouters/forensics.py—POST /forensics/watermark/identifyhandlers/config_delivery.py— apply watermark on every deliveryITL_WATERMARK_SECRET,ITL_WATERMARK_KEY_VERSIONadd_watermark_registry_tableAcceptance Criteria
WatermarkRegistryrowPOST /forensics/watermark/identifyreturns correct machine + delivery time for a valid fragment_itl_wmdoes not break MachineConfig schema validationITL_WATERMARK_ENABLED=falsedisables watermarking (default true)