package bundle import "sort" // This file is the host-agnostic CAPABILITY / RISK surfacing layer that AUGMENTS // (never replaces) the existing malicious/benign bundle label. It is a pure // taxonomy + presentation layer over res.Findings already extracted by the // analyzers: NO AST, NO new detection, NO Severity changes. // // The core robustness property: capabilities are driven by HOST-AGNOSTIC // findings (what a script CAN DO), not by the corpus's own defanged exfil host. // exfil-host-reference (which matches attacker.example literally) is demoted to // evidence_only NETWORK_EGRESS support and never acts as a capability driver, so // swapping attacker.example for a novel host does NOT silence the exfil-capable // combo (which fires via the host-agnostic exfil-env-to-network source+sink // co-occurrence). // CapabilityName identifies one host-agnostic thing a bundled script can do. type CapabilityName string const ( CapSecretAccess CapabilityName = "SECRET_ACCESS" CapNetworkEgress CapabilityName = "NETWORK_EGRESS" CapOpaqueExecution CapabilityName = "OPAQUE_EXECUTION" CapDynamicFetchExec CapabilityName = "DYNAMIC_FETCH_EXEC" CapCodeExecution CapabilityName = "CODE_EXECUTION" CapRegistryTamper CapabilityName = "REGISTRY_TAMPER" CapFSDestructive CapabilityName = "FS_DESTRUCTIVE" CapObfuscation CapabilityName = "OBFUSCATION" CapAntiAnalysis CapabilityName = "ANTI_ANALYSIS" CapPersistence CapabilityName = "PERSISTENCE" ) // RiskTier is the combos-only risk ranking surfaced alongside the back-compat // label. REVIEW is pinned to the existing escalation decision; ELEVATED/INFO/ // CLEAN rank the non-escalating remainder by capability power. type RiskTier string const ( TierClean RiskTier = "CLEAN" TierInfo RiskTier = "INFO" TierElevated RiskTier = "ELEVATED" TierReview RiskTier = "REVIEW" ) // Evidence is a single finding-derived datum supporting a capability. It carries // the originating sibling/member, line, signal, and human-readable detail so the // capability card can show operators exactly where the behavior was observed. type Evidence struct { File string `json:"file"` Line int `json:"line"` Signal string `json:"signal"` Detail string `json:"detail"` } // Capability is one host-agnostic capability present in a bundle, with its // power class ("high"|"low") and the evidence that produced it. type Capability struct { Name string `json:"name"` Power string `json:"power"` Evidence []Evidence `json:"evidence"` } // BigNasty is one big-nasty capability COMBINATION that fired, with a // plain-English explanation of why it is dangerous. The big_nasties list is // always computed and reported: it explains WHY a REVIEW verdict fired. type BigNasty struct { Name string `json:"name"` Why string `json:"why"` } // CapabilityProfile is the full host-agnostic risk surface for a bundle: the // capabilities present, the big-nasty combos that fired, and the derived tier. type CapabilityProfile struct { Capabilities []Capability `json:"capabilities,omitempty"` BigNasties []BigNasty `json:"big_nasties,omitempty"` Tier RiskTier `json:"risk_tier"` } // signalCapabilityMap maps each emitted Finding.Signal to the host-agnostic // capabilities it drives. exfil-host-reference is deliberately NOT here as a // driver — it is host-specific (matches attacker.example) and lives in // evidenceOnlySignals/evidenceDecorates, only decorating NETWORK_EGRESS. var signalCapabilityMap = map[string][]CapabilityName{ "env-credential-access": {CapSecretAccess}, "exfil-env-to-network": {CapSecretAccess, CapNetworkEgress}, "remote-code-execution": {CapDynamicFetchExec}, "reverse-shell": {CapNetworkEgress, CapCodeExecution}, "scheduled-network-callback": {CapNetworkEgress, CapPersistence}, "persistence": {CapPersistence}, "eval-decoded-payload": {CapOpaqueExecution, CapObfuscation}, "ships-opaque-executable": {CapOpaqueExecution}, "opaque-bytecode": {CapOpaqueExecution}, "ships-compiled-bytecode": {CapOpaqueExecution}, "suspicious-native-symbols": {CapOpaqueExecution}, "opaque-archive": {CapOpaqueExecution}, "opaque-archive-member": {CapOpaqueExecution}, "opaque-image": {CapOpaqueExecution}, "opaque-notebook": {CapOpaqueExecution}, "compiled-source-mismatch": {CapOpaqueExecution}, "compiled-without-matching-source": {CapOpaqueExecution}, "archive-contains-executable": {CapOpaqueExecution, CapAntiAnalysis}, "delegates-to-bundled-script": {CapCodeExecution}, "delegates-to-data": {CapCodeExecution}, "delegates-to-image": {CapCodeExecution}, "symlinked-executable-reference": {CapCodeExecution}, "allowed-tools-nl-directive": {CapCodeExecution}, "registry-rewrite": {CapRegistryTamper}, "destructive-command": {CapFSDestructive}, "embedded-encoded-blob": {CapObfuscation}, "image-embedded-blob": {CapObfuscation}, "data-embedded-directive": {CapObfuscation}, "image-embedded-directive": {CapObfuscation}, "padding-evasion": {CapObfuscation}, "archive-path-traversal": {CapAntiAnalysis}, "archive-bomb-guard": {CapAntiAnalysis}, "archive-too-deep": {CapAntiAnalysis}, "archive-member-limit": {CapAntiAnalysis}, } // evidenceOnlySignals contribute evidence (or scan-coverage notes) but never act // as a capability driver. exfil-host-reference is host-specific and is treated // as supporting evidence for NETWORK_EGRESS only; references-unscanned-filetype // and analyzer-error are scan-limitation notes (no capability at all). var evidenceOnlySignals = map[string]bool{ "exfil-host-reference": true, // host-specific (attacker.example); decorates NETWORK_EGRESS only "references-unscanned-filetype": true, // scan-limitation note "analyzer-error": true, // scan-limitation note } // evidenceDecorates maps a host-specific evidence_only signal to the capability // its evidence attaches to. It NEVER creates the capability — the entry only // appends evidence when that capability is already (or also) present-driven, or // surfaces the host-specific marker under that capability's evidence list. The // capability's PRESENCE for combo purposes is still governed by host-agnostic // drivers in signalCapabilityMap. var evidenceDecorates = map[string]CapabilityName{ "exfil-host-reference": CapNetworkEgress, } // highPowerCaps marks the capabilities whose mere presence (without a combo) // warrants ELEVATED. Low-power capabilities (CODE_EXECUTION-of-readable-script, // OBFUSCATION, ANTI_ANALYSIS) only reach INFO on their own. var highPowerCaps = map[CapabilityName]bool{ CapSecretAccess: true, CapNetworkEgress: true, CapOpaqueExecution: true, CapDynamicFetchExec: true, CapRegistryTamper: true, CapFSDestructive: true, } // BuildCapabilityProfile is a PURE function over the already-extracted findings. // It does NO new detection and NO AST: it folds each Finding through the // host-agnostic signal->capability map, attaches host-specific evidence to the // capabilities it decorates, classifies power, and computes the big-nasty // combos. The returned profile's Tier is left zero-valued (CLEAN's zero value is // the empty string, not TierClean) and MUST be set by ComputeTier at the call // site, which pins REVIEW to the existing escalation decision. func BuildCapabilityProfile(findings []Finding) CapabilityProfile { present := map[CapabilityName][]Evidence{} signals := map[string]bool{} for _, f := range findings { signals[f.Signal] = true ev := Evidence{File: f.File, Line: f.Line, Signal: f.Signal, Detail: f.Detail} for _, c := range signalCapabilityMap[f.Signal] { present[c] = append(present[c], ev) } // Host-specific evidence decorates an existing/also-driven capability but // never drives it on its own — append only when the capability is already // present (driven by a host-agnostic finding). This guarantees no // capability can be conjured purely by the host-specific match. if dec, ok := evidenceDecorates[f.Signal]; ok { if _, driven := present[dec]; driven { present[dec] = append(present[dec], ev) } } } caps := make([]Capability, 0, len(present)) for name, evs := range present { power := "low" if highPowerCaps[name] { power = "high" } caps = append(caps, Capability{Name: string(name), Power: power, Evidence: evs}) } sortCaps(caps) return CapabilityProfile{ Capabilities: caps, BigNasties: detectBigNasties(present, signals), } } // sortCaps orders capabilities deterministically by name so JSON/SARIF output // and test assertions are stable across runs (map iteration is unordered). func sortCaps(caps []Capability) { sort.Slice(caps, func(i, j int) bool { return caps[i].Name < caps[j].Name }) } // detectBigNasties computes the host-agnostic capability COMBINATIONS that drive // the "why" behind a REVIEW. The combos are a documented SUPERSET of // bundleEscalates's behavioral triggers so the plain-English explanation never // contradicts the verdict. Critically, exfil-capable fires on the fused // exfil-env-to-network finding (SECRET_ACCESS+NETWORK_EGRESS) OR on // env-credential-access co-occurring with any NETWORK_EGRESS-driving sink — it // NEVER requires exfil-host-reference, so it survives a host swap. func detectBigNasties(present map[CapabilityName][]Evidence, signals map[string]bool) []BigNasty { has := func(c CapabilityName) bool { _, ok := present[c]; return ok } var out []BigNasty if signals["reverse-shell"] { out = append(out, BigNasty{ Name: "remote-shell", Why: "Opens a reverse/bind shell — hands an attacker an interactive shell on the host, independent of any destination string.", }) } if signals["scheduled-network-callback"] { out = append(out, BigNasty{ Name: "scheduled-phone-home", Why: "Installs a persistent/scheduled job that performs network I/O — a recurring callout that survives restarts.", }) } if has(CapSecretAccess) && has(CapNetworkEgress) { out = append(out, BigNasty{ Name: "exfil-capable", Why: "Reads a credential AND opens a network sink — can steal secrets and ship them off-box, regardless of destination host.", }) } if has(CapOpaqueExecution) { out = append(out, BigNasty{ Name: "runs-uninspectable-code", Why: "Executes code that cannot be read (compiled/opaque artifact or source-mismatched binary, the xz pattern).", }) } if has(CapDynamicFetchExec) { out = append(out, BigNasty{ Name: "fetch-and-run", Why: "Downloads remote code and runs it immediately — payload is whatever the server returns at runtime.", }) } if has(CapObfuscation) && (has(CapNetworkEgress) || has(CapCodeExecution) || has(CapOpaqueExecution)) { out = append(out, BigNasty{ Name: "hidden-and-active", Why: "Hidden/encoded content combined with an active execution or egress capability — concealing live behavior.", }) } if has(CapRegistryTamper) { out = append(out, BigNasty{ Name: "external-registry-redirect", Why: "Rewrites package/registry config to redirect installs to an external endpoint — supply-chain redirect.", }) } if has(CapFSDestructive) { out = append(out, BigNasty{ Name: "data-destruction", Why: "Issues mass-destructive filesystem commands capable of wiping user data.", }) } return out } // ComputeTier ranks a bundle into a RiskTier. REVIEW is PINNED to the existing // label decision (escalatedOrMalicious := scorerMalicious || bundleEscalates) so // the derived tier — and therefore the derived label — can NEVER diverge from // today's bundle label on the corpus. The combo taxonomy does NOT gate REVIEW; // it only ranks the NON-escalating remainder into ELEVATED/INFO/CLEAN by the // power of the host-agnostic capabilities present. func ComputeTier(escalatedOrMalicious bool, prof CapabilityProfile) RiskTier { if escalatedOrMalicious { return TierReview } high := false low := false for _, c := range prof.Capabilities { if c.Power == "high" { high = true } else { low = true } } switch { case high: return TierElevated case low: return TierInfo default: return TierClean } } // DeriveLabel keeps the back-compat bundle label byte-identical to today's: // malicious iff REVIEW. Since REVIEW is pinned to (scorerMalicious || // bundleEscalates), this equals the exact OR that MakeBundleVerdict uses to set // the label today, guaranteeing ZERO regression on the 240-bundle eval. func DeriveLabel(tier RiskTier) string { if tier == TierReview { return "malicious" } return "benign" }