Skip to content

Add distributed multi-source origination and TLS fingerprint control to the scenario engine #36

Description

@NickCrew

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

  • A scenario can issue requests from ≥2 genuinely distinct network sources
    (distinct source IP as observed by the target), selectable per step.
  • A scenario can present ≥2 distinct TLS fingerprints (distinct JA3/JA4 as
    observed by the target), shared or rotating per step.
  • Origin/TLS selection is expressed in the scenario schema and surfaced in
    reports alongside the existing runner summary.
  • Selected origins are validated through the existing outbound allowlist.
  • At least one curated scenario exercises the path end-to-end against a
    Synapse detector (HeaderProfiler / TLS controls).

Metadata

Metadata

Assignees

No one assigned

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions