attacksim

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package attacksim is a SAFE, offline adversary-emulation harness. It does not exploit anything: it carries a curated set of ATT&CK-for-Containers TTPs as inert, well-bounded *descriptors* and asks the security controls under test whether they would fire (deny at admission, or detect at runtime). It is control-VALIDATION, not an exploit kit — nothing here starts a process, opens a socket, writes outside a temp dir, or touches real infrastructure.

The harness is deliberately decoupled from the controls it validates: Phase 4 (admission) and Phase 5 (runtime detection) plug in by implementing the small Control interface (see controls.go). Until those phases exist, the package ships a reference PolicyControl and a fixture-backed control so scenarios can be validated end-to-end today. Everything is deterministic (scenarios sort by ID) and gated behind an explicit authorization acknowledgement.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotAuthorized = errors.New("attacksim: run not authorized — set Options.Authorized and Options.Acknowledgement")

ErrNotAuthorized is returned when Run is called without an explicit opt-in. Adversary emulation must never run by accident.

Functions

func AckPhrase

func AckPhrase() string

AckPhrase returns the exact acknowledgement string a caller must supply. It is exported so CLIs and tests reference the single source of truth.

Types

type Baseline

type Baseline struct {
	// Fired maps scenario ID -> did a control fire when this baseline was taken.
	Fired map[string]bool `json:"fired"`
}

Baseline records, per scenario ID, whether a control fired at a known-good point in time. It is deliberately tiny and JSON-serializable so it can be checked into a repo and diffed like any other artifact.

func BaselineFrom

func BaselineFrom(rep *Report) Baseline

BaselineFrom builds a Baseline snapshot from a completed run, so today's green run becomes tomorrow's regression yardstick.

func LoadBaseline

func LoadBaseline(data []byte) (Baseline, error)

LoadBaseline parses a Baseline from JSON.

type Control

type Control interface {
	// Name is a stable identifier for the control in reports.
	Name() string
	// Kind reports whether this is an admission or detection control.
	Kind() ControlKind
	// Evaluate returns the control's verdict for an inert event. It must never
	// execute the action — only reason about its descriptor.
	Evaluate(ctx context.Context, e Event) Verdict
}

Control is a defensive control the harness can probe. Implementations must be pure and deterministic over an Event: no wall clock, no randomness, no I/O.

type ControlKind

type ControlKind string

ControlKind distinguishes the two defensive layers a scenario can exercise.

const (
	// KindAdmission is a preventive control that should deny a bad request
	// before it is admitted (Phase 4).
	KindAdmission ControlKind = "admission"
	// KindDetection is a runtime control that should raise an alert when a bad
	// action occurs (Phase 5).
	KindDetection ControlKind = "detection"
)

type ControlSet

type ControlSet struct {
	// contains filtered or unexported fields
}

ControlSet is an ordered collection of controls. The harness asks the set, filtered by the kind a scenario expects, whether anything fires.

func NewControlSet

func NewControlSet(cs ...Control) *ControlSet

NewControlSet builds a set from the given controls, preserving order.

func (*ControlSet) Add

func (s *ControlSet) Add(c Control)

Add appends a control (e.g. a real Phase 4 admission controller at wiring time).

type Event

type Event struct {
	Technique  string            // ATT&CK technique id, e.g. "T1611"
	Tactic     string            // ATT&CK tactic name, e.g. "Privilege Escalation"
	Action     string            // short verb phrase, e.g. "create privileged pod"
	Target     string            // what it acts on, e.g. "pod/attacker"
	Attributes map[string]string // machine-matchable properties of the action
}

Event describes, in data only, the adversary action a scenario represents. It is never executed. Attributes carry the specific bad properties (e.g. privileged=true, hostPath=/) that a control matches on — the same shape a real admission request or runtime event would expose, so a real Phase 4/5 control can evaluate it unchanged.

type FixtureControl

type FixtureControl struct {
	// contains filtered or unexported fields
}

FixtureControl replays recorded verdicts keyed by ATT&CK technique. It is how tests pin "this control fires for T1611" without any real control present, and how a recorded baseline of a real control can be checked into testdata. A missing technique means the control did not fire (an honest gap).

func LoadFixtureControl

func LoadFixtureControl(data []byte) (*FixtureControl, error)

LoadFixtureControl parses a recorded control from JSON of the form {"name":"...","kind":"admission","fires":{"T1611":true,...}}.

func NewFixtureControl

func NewFixtureControl(name string, kind ControlKind, fires map[string]bool) *FixtureControl

NewFixtureControl builds a fixture control from a technique→fired map.

func (*FixtureControl) Evaluate

func (f *FixtureControl) Evaluate(_ context.Context, e Event) Verdict

Evaluate looks up the event's technique in the recorded map.

func (*FixtureControl) Kind

func (f *FixtureControl) Kind() ControlKind

func (*FixtureControl) Name

func (f *FixtureControl) Name() string

type Options

type Options struct {
	// Authorized must be true and Acknowledgement must equal AckPhrase() for a
	// run to proceed. Two independent signals, so neither a stray true nor a
	// copied string alone is enough.
	Authorized      bool
	Acknowledgement string
	// Only, when non-empty, restricts the run to these scenario IDs.
	Only []string
}

Options gates and scopes a harness run. The zero value refuses to run (safe by default). Only include specifies a subset of scenario IDs; empty means all.

type PolicyControl

type PolicyControl struct {
	// contains filtered or unexported fields
}

PolicyControl is a built-in reference control. matchers maps an attribute key to the value that should trip it; presence of the key with that value (or, for "*", any non-empty value) fires the control.

func ReferenceAdmissionControl

func ReferenceAdmissionControl() *PolicyControl

ReferenceAdmissionControl returns a PolicyControl that denies the pod-shaped bad properties an admission webhook would reject.

func ReferenceDetectionControl

func ReferenceDetectionControl() *PolicyControl

ReferenceDetectionControl returns a PolicyControl that alerts on the runtime behaviors a detection engine would flag.

func (*PolicyControl) Evaluate

func (p *PolicyControl) Evaluate(_ context.Context, e Event) Verdict

Evaluate fires when the event carries any attribute the control matches on. It is deterministic and side-effect free; matched keys are reported sorted so the reason string is stable.

func (*PolicyControl) Kind

func (p *PolicyControl) Kind() ControlKind

func (*PolicyControl) Name

func (p *PolicyControl) Name() string

type Regression

type Regression struct {
	ScenarioID string
	Technique  string
	Name       string
	Severity   string
	WasFiring  bool
	NowFiring  bool
}

Regression is a scenario whose defense weakened relative to the baseline: it used to fire and now does not (the dangerous direction). Newly-firing controls are improvements, not regressions, and are not reported here.

func CompareBaseline

func CompareBaseline(current *Report, baseline Baseline) []Regression

CompareBaseline returns the regressions between a baseline and a current run, sorted by scenario ID. An empty result means every previously-working control still fires — the outcome you want from a scheduled validation agent.

type Report

type Report struct {
	Results   []ScenarioResult
	Total     int
	Validated int // scenarios where a control fired as expected
	Gaps      int // scenarios where no control fired (defenses did not hold)
}

Report is the full validation run: per-scenario results plus quick counts.

func Run

func Run(ctx context.Context, scenarios []Scenario, controls *ControlSet, opts Options) (*Report, error)

Run validates scenarios against the control set. It returns ErrNotAuthorized unless the caller has explicitly opted in. It never executes any scenario — it only evaluates each inert Event against the controls.

type Scenario

type Scenario struct {
	ID          string      // DS-RAT-ATK-NNN
	Technique   string      // ATT&CK technique id
	TacticName  string      // ATT&CK tactic
	Name        string      // short human name
	Description string      // what it does and why it matters
	Event       Event       // the inert action
	Expect      ControlKind // which control layer must fire
	Severity    string      // CRITICAL|HIGH|MEDIUM if the control fails to fire
	References  []string    // ATT&CK / hardening links
}

Scenario is one curated, safe adversary technique the harness can validate. Expect names which control layer *should* stop or catch it; Severity is how serious an undetected gap would be.

func Builtin

func Builtin() []Scenario

Builtin returns the standard scenario catalog, sorted by ID for determinism. Callers may pass a subset to the harness, but the default is the full set.

type ScenarioResult

type ScenarioResult struct {
	Scenario Scenario
	Verdicts []Verdict
	Fired    bool // at least one expected-kind control fired
	Gap      bool // no expected-kind control fired — a validation failure
}

ScenarioResult is the outcome of validating one scenario: the verdicts from every relevant control and whether the defense held (Fired) or a Gap exists.

type Verdict

type Verdict struct {
	Control string
	Kind    ControlKind
	Fired   bool
	Reason  string
}

Verdict is a control's answer for one event: did it fire, which control, and why. A gap is simply the absence of any firing verdict where one was expected.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL