Summary
Crucible's scenario engine can today simulate a distributed, multi-source
campaign only at the HTTP application layer. It cannot orchestrate one at
the network/transport layer. This issue tracks closing that gap so the
engine can validate defenders that key on the real network source or the TLS
handshake — not just on request headers.
Current state (the boundary)
- All outbound traffic egresses from a single process through one
fetch()
call (apps/demo-dashboard/src/server/engine.ts:790). One real TCP source,
one TLS stack.
- "Many origins" is modeled as header values: per-step
User-Agent and
X-Forwarded-For (see packages/catalog/scenarios/api-demo-botnet-showcase.json
— "Bot Node N (US East / EU West / …)" — and
packages/catalog/scenarios/distributed-api-reconnaissance-swarm.json).
- Timing is controllable:
execution.delayMs, execution.jitter,
execution.iterations, plus executionMode: parallel / parallelGroup
batching and a dependsOn/when dependency DAG. (Not in scope here.)
- There is no egress proxy/dispatcher pool, no
localAddress binding, no
distributed runner fan-out, and no JA3/JA4 control. A grep of the server for
httpsAgent|proxy|dispatcher|localAddress|undici|socks finds only the
proxy-authorization header-redaction entry in reports.ts.
Consequence: against a WAF that trusts/parses X-Forwarded-For or
rate-limits on the claimed IP and fingerprints on User-Agent, the simulation
is faithful. Against one that keys on real source IP, JA3/JA4, or TCP-level
behavior, the "distributed campaign" collapses to one client and the scenario
tests nothing.
Why now — the offense/defense asymmetry
The defender side already has fingerprint-class detection filed on Synapse,
with no offense-side counterpart to validate it:
So the product line plans to detect these fingerprints but has no way to
generate genuinely distinct ones to test the detection. That is a real
test-coverage gap, not just a missing feature.
Scope — two deliverables
1. Distributed origination (network-layer source distribution)
Pluggable egress so a step can present a genuinely different network source:
2. TLS fingerprint control (transport-layer identity)
- Swap the HTTP client for one that exposes JA3/JA4 control (curl-impersonate
or a uTLS-backed runner) so fingerprints rotate at the transport layer, not
just in headers.
- Schema surface for shared-vs-rotating TLS profiles per origin/step.
Out of scope
Related
Acceptance criteria
Summary
Crucible's scenario engine can today simulate a distributed, multi-source
campaign only at the HTTP application layer. It cannot orchestrate one at
the network/transport layer. This issue tracks closing that gap so the
engine can validate defenders that key on the real network source or the TLS
handshake — not just on request headers.
Current state (the boundary)
fetch()call (
apps/demo-dashboard/src/server/engine.ts:790). One real TCP source,one TLS stack.
User-AgentandX-Forwarded-For(seepackages/catalog/scenarios/api-demo-botnet-showcase.json— "Bot Node N (US East / EU West / …)" — and
packages/catalog/scenarios/distributed-api-reconnaissance-swarm.json).execution.delayMs,execution.jitter,execution.iterations, plusexecutionMode: parallel/parallelGroupbatching and a
dependsOn/whendependency DAG. (Not in scope here.)localAddressbinding, nodistributed runner fan-out, and no JA3/JA4 control. A grep of the server for
httpsAgent|proxy|dispatcher|localAddress|undici|socksfinds only theproxy-authorizationheader-redaction entry inreports.ts.Consequence: against a WAF that trusts/parses
X-Forwarded-Fororrate-limits on the claimed IP and fingerprints on
User-Agent, the simulationis faithful. Against one that keys on real source IP, JA3/JA4, or TCP-level
behavior, the "distributed campaign" collapses to one client and the scenario
tests nothing.
Why now — the offense/defense asymmetry
The defender side already has fingerprint-class detection filed on Synapse,
with no offense-side counterpart to validate it:
(would flag the rotating UA / XFF).
So the product line plans to detect these fingerprints but has no way to
generate genuinely distinct ones to test the detection. That is a real
test-coverage gap, not just a missing feature.
Scope — two deliverables
1. Distributed origination (network-layer source distribution)
Pluggable egress so a step can present a genuinely different network source:
undiciDispatcher, orlocalAddressbinding across an allocated IP block; or fan steps out todistributed / cloud k6 runner agents.
layered on the existing external-runner seam (Add external runner steps for k6 and nuclei in Crucible assessments #24, Implement nuclei runner execution and findings summaries on the external runner seam #25).
engine outbound allowlist (cf. Document and harden DNS-rebinding limits for ScenarioEngine outbound allowlists #12 DNS-rebinding hardening).
2. TLS fingerprint control (transport-layer identity)
or a uTLS-backed runner) so fingerprints rotate at the transport layer, not
just in headers.
Out of scope
steps). See Implement Adaptive Execution (Safe-Mode Throttling) #11 (Safe-Mode Throttling) and Extend scenario schema with execution stages and pass/fail thresholds #21 (execution stages/thresholds).
reporter of curated runs; this adds origination fidelity, not a load platform.
Related
Acceptance criteria
(distinct source IP as observed by the target), selectable per step.
observed by the target), shared or rotating per step.
reports alongside the existing runner summary.
Synapse detector (HeaderProfiler / TLS controls).