Decepticon can send anonymous usage telemetry to help maintainers see what users ask the agents to do and what the agents actually do. Decepticon is free/OSS; this sharing helps fund and improve it. It is opt-out — the onboard wizard asks for consent (default yes) and you can turn it off at any time — and designed for a red-team threat model: raw prompts, targets, credentials, and tool output are never transmitted.
- On by default for consenting users (opt-out). The onboard wizard asks
during setup (default yes), writing
DECEPTICON_TELEMETRY=research. Existing users are re-asked once atdecepticon startafter this policy change. - Turn it off anytime: set
DECEPTICON_TELEMETRY=off(orbasic) in~/.decepticon/.env, rundecepticon-cli telemetry off, orDO_NOT_TRACK=1. - Nothing is sent without a
DECEPTICON_TELEMETRY_ENDPOINT(shipped in the.envtemplate; backfilled into existing installs on update). - See exactly what would be sent:
decepticon-cli telemetry preview.
| Variable / command | Effect |
|---|---|
DECEPTICON_TELEMETRY=off|basic|research |
consent mode (template default research; unset ⇒ off) |
DO_NOT_TRACK=1 |
standard kill switch — forces off |
BENCHMARK_MODE=1 |
forces off — benchmark prompts are harness-generated, not user activity |
DECEPTICON_TELEMETRY_ENDPOINT=<url> |
gateway URL; unset ⇒ nothing is sent |
decepticon-cli telemetry status |
show resolved mode / endpoint / anonymous id |
decepticon-cli telemetry preview |
print the exact payload for a sample run |
decepticon-cli telemetry off / on |
persistent opt-out marker (overrides env) |
Two consent tiers map to the data tiers in the design doc:
-
basic→ Tier A (structural ground truth, always safe): event type, agent name, tool name (e.g.nmap), normalized status, bucketed sizes, token counts, model id — plus the classification the engagement itself produces, derived from theFindingmodel and OPPLAN tracker (not inferred from your prompt):Event Fields collected Never collected finding.createdseverity,cwe,mitre_techniques,phase,confidence,detected(purple-team),agentfinding title/description, affected_target, evidence, PoCopplan.updatephase(recon→…→exfiltration),status_objective(pending/blocked/…)objective title/notes tool.resulttool,status,output_buckettool output This is how maintainers learn what the tool actually finds and where engagements stall (e.g. CWE/severity distribution = what it detects;
blockedclusters at a phase = where it fails) — entirely from the agent's structured artifacts, never from prompt text. -
research→ the reasoning corpus: additionally the red-team reasoning — your objectives, the agent's chain-of-thought / tactic rationale, the commands it runs, and the observations — captured as-is so the attacker reasoning is preserved for training future autonomous red-team agents. The chain-of-thought is whatever the model actually produced (extended-thinking blocks included); harness-injected<system-reminder>blocks are stripped from your turns, so what is recorded as human input is what you wrote. Target identifiers are MASKED (10.0.0.5→<HOST_1>, creds →<CRED_1>) so the reasoning stays intact but no real target/credential is shared. Enable withdecepticon-cli telemetry enable research(it prints the disclosure first).Consent boundary: the agent's reasoning is yours to share. The target's data is not yours to consent away, so it is masked even here.
What masking actually guarantees — and what it does not. Masking is pattern-based plus whatever your engagement declared. It reliably removes structured identifiers (IPs, MACs, emails, URLs, private keys, JWTs, cloud access keys) and the identity your RoE declares (client organization, engagement name/slug, authorizer, in-scope hosts) — which is why filling in the client field when the RoE is created matters.
It is not a guarantee against everything. A company or product name typed into free prose, a credential phrased in a language the patterns do not cover, or a distinctive description of an asset can survive. Published research also shows that LLMs can re-identify subjects from context alone even after identifiers are removed. Treat
researchas "identifiers are stripped and the corpus is handled as sensitive", not as anonymization. If your engagement cannot tolerate that, usebasicoroff.
One extra event type, telemetry.drop, reports how many events Decepticon's own
fail-closed scanner discarded before sending, counted by class (e.g.
{"category": "ipv4", "count": 3}). It carries the class and a number only —
never the content that was dropped — and exists so silent over-dropping is
visible rather than mistaken for an idle install.
Every batch carries a non-identifying envelope: a random install_id (a UUID
minted on first use — never machine- or IP-derived), the Decepticon version, and
the OS family (linux/darwin/windows).
{
"schema_version": "1.0",
"tier": "A",
"install_id": "1e9a73a6-c8bd-4e1e-be02-78f4b11de4e1",
"client": { "decepticon_version": "1.1.13", "os": "linux" },
"events": [
{ "type": "tool.call", "ts": 2.0, "agent": "recon", "tool": "bash" },
{ "type": "tool.result", "ts": 3.0, "agent": "recon", "tool": "bash",
"status": "ok", "output_bucket": "1k-10k" },
{ "type": "finding.created", "ts": 4.0, "agent": "exploit",
"tool": "validate_finding", "cwe": ["CWE-89"], "mitre_techniques": ["T1190"] }
]
}Each step carries a role (human input / agent output / tool execution), a
per-engagement session_id, and a monotonic step — so the whole
trajectory reconstructs in order (WHERE session_id = X ORDER BY step) into the
turn sequence a training pipeline needs. Identifiers are masked throughout:
{
"schema_version": "1.0",
"tier": "R",
"install_id": "1e9a73a6-…",
"client": { "decepticon_version": "1.1.13", "os": "linux" },
"events": [
{ "type": "trajectory.step", "session_id": "a1b2c3d4e5f60718", "step": 0,
"role": "human", "agent": "decepticon", "text": "Objective: own the host at <HOST_1>" },
{ "type": "trajectory.step", "session_id": "a1b2c3d4e5f60718", "step": 1,
"role": "agent", "agent": "exploit",
"text": "the login at <DOMAIN_1> on <HOST_1> looks injectable — try UNION-based SQLi" },
{ "type": "trajectory.step", "session_id": "a1b2c3d4e5f60718", "step": 2,
"role": "tool", "agent": "exploit", "tool": "bash",
"args_text": "sqlmap -u <URL_1> --batch", "observation": "dumped 12 rows from <HOST_1>" }
]
}The reasoning structure is intact (training value preserved); <HOST_1> is the
same placeholder every time that host recurs in the session, but the real target
/ credentials never leave the machine. session_id is a hash (the engagement
name may carry a client/org name, so it is never sent raw).
Target IPs / domains / hosts, credentials, keys and tokens are blocked by three layers:
- Shape redaction at the source —
EventLogMiddlewarerecords shapes, not contents (<str:42>,***REDACTED***), for thebasictier. - Client Tier-C scan — before anything is queued, a fail-closed scanner
drops any event still matching an IP / cred / host pattern. Drops are
reported as a
telemetry.dropcount, never as content. - Gateway Tier-C reject — the ingest gateway re-scans and rejects, and drops your IP (it never reaches the analytics backend).
Layers 2 and 3 are pattern-based, which bounds what they can promise: see
the research tier notes above for what survives. They are a floor, not
anonymization.
- Recipient: PurpleAILAB, the Decepticon maintainers. Batches go to a Cloudflare Worker we operate, which forwards to our PostHog project. The Worker never records your IP and disables geo-enrichment.
- Purpose: improving Decepticon, and — for the
researchtier — building a training corpus for future autonomous red-team agents. - Identity: a random
install_id(never machine- or IP-derived) plus a per-engagementsession_idthat is a salted hash. Neither is linked to an account; we cannot contact you from telemetry alone. - Retention: data is retained under our analytics backend's default
retention. A specific published retention window and a self-serve deletion
path are not yet in place — until they are, the reliable control is
turning telemetry off (
DECEPTICON_TELEMETRY=off,DO_NOT_TRACK=1, ordecepticon-cli telemetry off), which takes effect immediately. If you need data already sent to be removed, open an issue with yourinstall_id(decepticon-cli telemetry statusprints it).
Events are batched, gzipped, and sent best-effort to the gateway over HTTPS. Failures (offline, gateway down) are silently dropped — telemetry never blocks or breaks an engagement. The gateway holds the analytics backend credential, so the OSS client only ever knows the public endpoint URL.
See telemetry-gateway/README.md for the gateway, and
docs/design/2026-06-20-telemetry-data-collection-design.md for the full design.