Execution Modes

Mutant has three execution modes and one modifier. This document is the definitive statement of what each one changes; every row below is traced to the code that implements it.

Mutant has three execution modes and one modifier. This document is the definitive statement of what each one changes; every row below is traced to the code that implements it.

Mutant takes no configuration from environment variables, so the command line is the complete record of the posture a run used. See CONFIGURATION_POLICY.md.

The one-sentence version#

--compat weakens the response. --dev weakens the key.

Compatibility mode still requires your password and still verifies the artifact. It only declines to stop the run when a security probe fires. Developer mode does that too, and additionally falls back to a key that is public. An artifact built or run under --dev has no confidentiality.

The modes#

There are three, not four. --secure names the default; it is not a fourth mode.

Mode Intent Use it for
default (--secure) Ship it Release artifacts, untrusted input, evidence handling
--compat Run it where secure mode cannot Containers, CI, VMs — anywhere a probe fires on an ordinary host
--dev Edit-compile-run loop Local development only. Never a release artifact
--signer-auth A modifier, not a mode Combine with the default wherever provenance matters

Naming two modes on one command line is an error. --secure --compat and --secure --dev each exit non-zero naming both flags, rather than resolving to whichever came last. --dev --compat is accepted, because dev mode implies compatibility mode — that is redundant, not contradictory — and repeating a flag is harmless.

What each mode actually changes#

Behaviour default (--secure) --secure --signer-auth --compat --dev
Signature verification Embedded self-verify Ed25519 against a trusted public key Embedded self-verify Embedded self-verify
Anti-reversing probe passes 2 — pre-decode and pre-execution 2 1 — pre-decode only 1
Probe outcome terminate, with detector and remedy terminate warn to stderr, continue warn, continue
Tamper response terminate terminate warn warn
VM OpChkDbg / OpChkSnd halt with an explanation halt log and continue log and continue
VM integrity check terminate terminate warn, continue warn, continue
Security dev logging off off off on, at --security-log-level debug|trace
Password required required required falls back to the built-in key, announced

Sources: runner/runner.go — signature verification and probe passes; security/response_policy.go and security/profile.go — tamper response; vm/vm.go — security opcodes and integrity checks; main.go — mode resolution, logging, password fallback.

Security is monotonic in the mode. The set of checks a stronger mode performs is a superset of every weaker mode's. This was not always true: secure mode without --signer-auth once matched neither verification branch and verified nothing at all, while --compat self-verified — the most secure-sounding invocation performed the fewest checks. Self-verification is now the floor in every mode, and --signer-auth upgrades it.

`--signer-auth` and `--trusted-key`#

Self-verification proves internal consistency: the signature in the envelope matches the code, under the key travelling inside the envelope. It cannot prove who produced the artifact, because an attacker who re-signs a modified artifact with their own key produces something that self-verifies.

--signer-auth upgrades verification to a trusted public key, which is what establishes provenance. --trusted-key <path> names that key as a file holding hex-encoded key material; without it, verification uses a locally bootstrapped keypair, which trusts whatever signed the artifact on this host. Secure mode without --signer-auth prints one line saying self-verification is all it did.

--signer-auth and --no-signer-auth on the same command line is an error.

When secure mode stops the run#

Secure mode terminates when a probe reports a debugger, an analysis sandbox, injection or hooking activity in this process, or a hostile-scoring process elsewhere on the host. A termination prints what fired and what to do:

[security] event=sandbox_detected stage=pre-decode action=terminate
[security] detector=sandbox type=docker confidence=90 signals=cgroup:docker,/.dockerenv
[security] reason: secure mode does not run where the host looks like an analysis sandbox
[security] remedy: re-run with --compat if this host is expected to look like this.
[security]         --compat weakens the response only: a probe hit warns instead of stopping
[security]         the run. Your password is still required and the artifact is still verified.
sandbox detected, execution halted for security

A probe reports what the machine looks like, and an ordinary container, VM or CI runner looks enough like an analysis sandbox to trip one — which is exactly where forensic tooling runs. --compat is the supported answer to that false positive.

The artifact events do not offer --compat. A signature that does not verify, and bytecode that fails its own integrity check, are statements about the file rather than readings taken of the host. --compat would downgrade them to a warning and run the artifact anyway, so those events name the artifact as the thing to fix instead.

Two commands pick the posture for you. mutant test and mutant debug run their program with the responses advisory, as --compat does, and take no mode flag. Both are development activities on the developer's own machine, and for both the alternative was a command that could not do its job: secure mode ended every debug session launched on a virtual machine, before its first step. The probes are still compiled into the bytecode either command runs; only the verdict is advisory. See DEBUGGING.md.

Passwords#

A password is required in every mode. The only exception is --dev, and only when the command line names no password source at all: naming a source and having it fail is an error, not a reason to reach for the development key.

mutil.GetPwd() — the development key — is not a prompt and not random. It is a fixed HKDF-SHA512 derivation over three string constants compiled into the binary, so every Mutant binary ever built derives the identical key. Anyone with a copy of the binary can decrypt anything encrypted under it. Every use of it prints:

[dev] no password supplied; using the built-in development key -- not for release artifacts

--dev is refused outright for mutant release and mutant gen assets.

Choosing a posture#

Situation Command
Production, trusted release artifact mutant prog.mu --secure --signer-auth --trusted-key <path>
Production, no pinned signer yet mutant prog.mu --secure --signer-auth
A probe fires on a container, VM or CI runner mutant prog.mu --compat
Local development mutant prog.mu --dev

--secure is the default; naming it explicitly is how an incident note records the posture unambiguously. Nothing needs resetting afterwards — a previous run cannot leave state that changes the next one.

See also#

Related reading