Security LLD Traceability Matrix
This document provides end-to-end traceability from security design intent to concrete implementation and validation.
1. Purpose#
This document provides end-to-end traceability from security design intent to concrete implementation and validation.
It maps:
- Security requirements and controls
- Implementation anchors (functions/files)
- Runtime configuration surfaces (flags/env)
- Test coverage and how it is enforced
- Residual gaps and next validation actions
2. Traceability Model#
Evidence levels used in this matrix:
I= implementedT= testedC= wired into the repository-widego test ./...gateP= partial / pending depthD= declined by decision: no control exists, none is planned, and the decision is recorded beside the row
3. Security Control Matrix#
| ID | Control Requirement | LLD Area | Implementation Anchors | Config Surface | Tests / CI Evidence | Status |
|---|---|---|---|---|---|---|
| SEC-001 | Signed artifact envelope must be parsed and verified before execution | Artifact format + trust model | security/signatures.go, security/signatures.go, security/signatures.go, runner/runner.go | Mode-driven path: --secure / --compat / --dev |
security/security_test.go, runner/runner_test.go | I/T/C |
| SEC-002 | Secure mode must pin signer identity to trusted key | Secure mode semantics | runner/runner.go, security/signatures.go, security/const.go | --trusted-key <path> |
security/security_test.go, runner/runner_test.go | I/T/C |
| SEC-003 | Signature failure handling must be policy-driven | Tamper response policy | runner/runner.go, runner/runner.go, security/response_policy.go | --secure / --compat / --dev |
security/security_test.go, runner/runner_test.go | I/T/C |
| SEC-004 | Payload confidentiality and integrity at rest must use AEAD | Crypto layer | security/crypto.go, security/crypto.go, security/const.go | Password input and metadata | indirect via runner decode path tests runner/runner_test.go | I/T/P |
| SEC-005 | Password-based key derivation must use bounded Argon2id params | KDF hardening | security/kdf.go, security/kdf.go, security/crypto.go | password mode + metadata fields | security/security_test.go | I/T |
| SEC-006 | Password quality policy required when explicit password mode is used | Password policy | security/kdf.go, generator/generate.go | prompt / --password-file / --password-stdin (-password refused) |
covered by generator path behavior and policy validation unit scope | I/P |
| SEC-007 | Runtime instruction decode must be offset-aware to reduce keystream reuse | VM decode hardening | vm/vm.go, code/code.go, code/code.go, security/secure_random.go | runtime password/seed context | security/security_test.go, security/security_test.go | I/T/C |
| SEC-008 | Runtime integrity checks must detect instruction tampering | VM integrity probes | vm/vm.go, vm/vm.go, vm/vm.go | policy + secure default behavior | vm/vm_security_policy_test.go | I/T/C |
| SEC-009 | Integrity failures must trigger telemetry and policy action | Telemetry + policy coupling | vm/vm.go, security/telemetry.go, security/response_policy.go | None; VM forces secure policy | vm/vm_security_policy_test.go, vm/vm_security_policy_test.go, vm/vm_security_policy_test.go | I/T/C |
| SEC-010 | Anti-debug checks must be staged before decode and before execution | Runtime gate enforcement | runner/runner.go, runner/runner.go, runner/runner.go | mode + tamper response env | policy behavior tests security/security_test.go | I/T/P |
| SEC-011 | Debugger detection must be platform-specific with weighted signal logic on Windows | Anti-debug platform design | security/antidebug.go, security/antidebug_windows.go, security/antidebug_weighting.go, security/antidebug_linux.go, security/antidebug_darwin.go | runtime OS selection | security/security_test.go | I/T/P |
| SEC-012 | Security telemetry must support atomic counters and secure export | Telemetry subsystem | security/telemetry.go, security/telemetry.go, security/telemetry.go | None; in-process API only | security/security_test.go, security/security_test.go | I/T/C |
| SEC-013 | CLI must clearly resolve secure/compat/dev mode and developer fallback semantics | CLI posture controls | main.go, main.go, main.go, main.go | --secure, --compat, --dev, --password-* |
operationally validated in local runtime use; no dedicated CLI parsing tests yet | I/P |
| SEC-014 | Generator must use a stable per-host signing identity | Signing workflow | generator/generate.go, generator/generate.go, security/key_bootstrap.go | None; local keystore only | indirectly validated by signature verification tests | I/P |
| SEC-015 | The security suites must run on every supported OS before a release | Release validation | CONTRIBUTING.md, SECURITY_LLD.md | None; go test ./... with CGO_ENABLED=0 |
the suites themselves; nothing automates the "every OS" half since the CI workflow was removed | I/P |
| SEC-016 | Protection profile must define default tamper behavior | Runtime policy profile | security/profile.go, security/response_policy.go | None; fixed at standard |
security/security_test.go | I/T |
| SEC-017 | Per-builtin capability configuration -- declined; none exists (note 1) | Builtin capability gates | None. A gate would have to cover: builtin/builtin.go, builtin/command_exec.go, builtin/fs.go, builtin/net.go, builtin/http.go | None. No per-builtin gate exists (note 1) | security/command_exec_bounds_test.go covers the fixed limits that do apply, there being no gate to test | D |
| SEC-018 | Standalone release artifacts must carry profile attestation and provenance | Release trailer attestation | generator/writebinary.go, runner/runner.go, security/profile.go, security/const.go | build profile + release generation path | runner/runner_test.go | I/T |
3.1 Note 1 -- SEC-017, per-builtin capability configuration#
There is no per-builtin capability gate, and none is planned for 2.6.0.
This is a decision taken on 2026-10-10, not an unfinished item: a Mutant
program carries the authority of the process that runs it, the same way a
program written in Python, Ruby, Node or Go does. None of those puts a
per-call gate in front of subprocess, os/exec or opening a socket
either.
What follows from that, stated plainly because a reader deciding whether to run a program they did not write needs it stated rather than softened:
- A program that can reach
exec_string,exec_argvorcmd_runcan run commands, and one that can reach thefs_*,net_*orhttp_*families can read files and open sockets, with this process's own permissions. - The operator's decision is whether to run the program, not what it may do once running. The controls that support that decision are the signed artifact envelope and the mode flags (SEC-001), not a capability set.
- What does constrain command execution is fixed and not configurable: a 3-second timeout bounding the whole call rather than one process, 8 KiB kept of each output stream, a kill that reaches the process tree, and a shell named rather than written out as a command line. Those are limits on blast radius, not permissions, and they are tested in security/command_exec_bounds_test.go.
- The LSP's
commandInjectionrule is an editor-time warning. It can be switched off and it does not run at execution time, so it is not an enforcement point. - The
policy_*builtins are not this control under another name. They wrap Open Policy Agent, so a program loads a Rego module and asks it a question, and the program itself decides what to do with the answer. Nothing outside those five builtins calls the engine, so it is never consulted before a builtin runs.
The design is revisited if a user asks for it. Until then this row exists so that a reviewer auditing control coverage finds a recorded decision rather than a gap, and so that nothing in this repository describes the control as pending.
4. Runtime Decision Trace#
5. Flag Traceability#
Every switch is a command-line flag. Mutant reads no environment variable for configuration, so this section is the complete control surface. See CONFIGURATION_POLICY.md, which also lists the variables the Go runtime and Mutant's libraries still read on its behalf.
- Mode-flag validation
validateModeFlagsrejects a command line naming two contradictory postures before any other work, so the selectors below are read from a command line that names at most one mode- anchor: main.go
--secure/-secure
- default secure posture selector and explicit assertion of it
- anchor: main.go
--compat/-compat
- compatibility posture selector
- anchor: main.go
--dev/-dev
- compatibility posture + default local password fallback for
.muwhen password omitted - anchors: main.go, main.go
- Password sources: prompt (default),
--password-file,--password-stdin,--password-insecure;-password/-pwd/--password=/--pwd=are parsed only so the resolver can refuse them by name (since 2.6.0)
- collected into a
credential.RequestbyextractPasswordRequest, then resolved bycredential.Resolver, which rejects a command line naming more than one source - the deprecated argv forms emit a warning naming the process-table exposure
- anchors: main.go, credential/credential.go
--signer-auth/--no-signer-auth
- upgrade signature verification to a trusted public key, or decline to; self-verification is the floor in every mode either way
- anchors: main.go, runner/runner.go
--trusted-key <path>
- file holding the hex-encoded ed25519 public key to verify against; falls back to the local keystore when absent
- anchors: main.go, security/key_bootstrap.go
--security-log-level <level>/--log-level <level>
- security logging verbosity in dev mode
- anchor: main.go
--timing
- per-stage run timing on stderr
- anchor: main.go
5.2 Fixed behaviour (no control surface)#
These were once environment variables and are now constants, with one entry that was never a control at all. Listed so a reviewer does not go looking for a control that used to exist, or never did:
- Protection profile --
standard(security/profile.go). - Tamper response -- derived from the mode flags above (security/response_policy.go).
- Tamper delay --
250ms; no mode selects thedelayresponse. - Anti-tamper probe gate -- always on (security/antitamper_probe.go).
- Process-protection gate -- always on (runner/runner.go).
- Remote process scan -- off; test-only setter (security/processscan_config.go).
- Audit stream and telemetry export -- no-op and uncalled respectively (security/telemetry.go).
- Signing key -- local keystore only (security/key_bootstrap.go).
- Builtin capability configuration -- never existed and is not planned; declined 2026-10-10. See note 1 under the control matrix.
6. Test Coverage Map by Attack Scenario#
| Attack Scenario | Expected Security Behavior | Primary Tests |
|---|---|---|
malformed .mu envelope in secure mode |
reject before decode | runner/runner_test.go |
| malformed envelope in compat mode | policy may continue; fail later during decode | runner/runner_test.go |
| tampered signer identity | secure mode rejects untrusted signer | runner/runner_test.go, security/security_test.go |
| trusted signer valid but payload unusable | signature path passes, decode fails correctly | runner/runner_test.go |
integrity tamper under warn/delay/terminate |
policy-specific continue/fail behavior with telemetry increment | vm/vm_security_policy_test.go |
| response policy default/override correctness | secure default terminate, compat default warn, env override honored | security/security_test.go, security/security_test.go |
| stream-mask roundtrip and offset byte correctness | decryptability and offset-specific correctness | security/security_test.go, security/security_test.go |
| telemetry JSON/export correctness | counters and file export valid | security/security_test.go, security/security_test.go |
| windows weak/high-confidence weighting | threshold behavior stable | security/security_test.go |
7. Known Traceability Gaps#
The following areas are represented in LLD but only partially evidenced at integration depth:
- Real Windows runner integration execution with genuine debugger signals (
Pdepth remains). - Full compile -> sign -> run -> tamper -> rerun lifecycle integration suite.
- Dedicated CLI flag parsing tests for secure/compat/dev precedence.
- Explicit unit coverage for generator password complexity rejection path.
- Signed-key rotation lifecycle tests (multi-key trust/rollover not yet implemented).
8. Recommended Validation Backlog#
- Add
mainCLI parsing tests covering mixed mode flag order and dev fallback behavior. - Add e2e fixture tests that produce real
.muartifacts and validate tamper outcomes in all policies. - Verify runtime anti-debug policy on a clean Windows host before each release. This was a CI job in the backlog; with no CI it is a release step, and it is manual.
- Done: negative tests for a malformed, wrong-sized and missing
--trusted-keyfile (security/key_bootstrap_test.go). - Add deterministic artifact compatibility tests to guard accidental secure/compat behavior drift.
9. Quick Audit Checklist (Reviewer Use)#
- Secure mode with
--signer-authresolves a trusted key, and a--trusted-keyfile that is missing or malformed fails the run rather than falling back. - Any signature, debugger, or integrity event routes through policy layer.
- Telemetry increments occur before policy returns error on terminate.
- VM operand/opcode decode remains offset-aware.
go test ./...has been run for this change — it includes the security suites and the configuration guard inpolicy/. Nothing runs it for you; say in the PR which OS you ran it on.- Dev mode remains explicit and does not silently alter secure mode defaults unless chosen.
10. Probe and Process-Protection Traceability#
10.1 Control Additions#
- Master anti-tamper probe gate:
antiTamperProbeEnabled, a compile-timetrue. Not configurable. - Runner process-protection gate:
isProcessProtectionEnabled(), which returnstrue. Not configurable. - Runner enforcement threshold: any probe signal with
detected=trueandconfidence >= 80. This is the only decision point left.
10.2 Implementation Anchors#
- Probe gate and engine:
security/antitamper_probe.go - Probe routing:
security/antitamper_routing.go - Probe implementations:
security/antitamper_detectors.gosecurity/antitamper_windows.go
- Runner enforcement path:
runner/runner.go - Builtin diagnostics probe use:
builtin/security_status.go
10.3 Operational Notes#
- Runner enforcement probe scope is intentionally narrower than builtin diagnostic scope.
- If the master probe gate is disabled, runner process-protection enforcement will not execute probe logic even when the process-protection gate is enabled. Only a test can reach that state.
11. 2026-07 Code Sync Addendum#
This addendum captures code-accurate deltas that must be read together with the matrix above.
11.1 Signer-Auth Runtime Semantics#
Current implementation:
- Secure mode selection and signer-auth are independent runtime switches.
- Trusted signer verification path runs only when
--signer-authis present. --no-signer-authkeeps secure-mode runtime gates but skips signature verification path in runner.
Anchors:
11.2 Remote Process Scan Control Surface#
Current implementation:
- Remote scan manager is gated by
remoteScanConfigState.Enabled, which isfalsein every shipped binary and writable only bySetRemoteScanConfigForTesting. - Mode is
remoteScanConfigState.Mode(off|observe|enforce, defaultobserve). - Runner blocks only on enforce-mode critical verdicts.
- Scan errors are non-blocking and telemetry-visible.
Anchors:
- security/processscan_config.go
- security/processscan_manager.go
- runner/runner.go
- runner/runner_test.go
11.3 Remote Scan Runtime Depth#
Current implementation status:
- Types/config/correlator/manager/telemetry and runner integration are implemented.
- Windows scanner implementation currently returns empty verdicts (
nil, nil), so enforcement path is wired but detector depth is still scaffolding-first.
Anchors:
End of document.