Skip to content

fix(engine): narrow the blanket notable-exec corroboration arm, land reverse_shell_on_foothold (ADR-0041) - #329

Open
thejefflarson wants to merge 2 commits into
mainfrom
thejefflarson/jef-393-narrow-the-blanket-notable-exec-corroboration-arm-land
Open

fix(engine): narrow the blanket notable-exec corroboration arm, land reverse_shell_on_foothold (ADR-0041)#329
thejefflarson wants to merge 2 commits into
mainfrom
thejefflarson/jef-393-narrow-the-blanket-notable-exec-corroboration-arm-land

Conversation

@thejefflarson

Copy link
Copy Markdown
Owner

Summary

Implements ADR-0041 (narrow the blanket notable-exec corroboration arm to shapes; PR #328, not yet on main — read from origin/corroboration-floor-narrowing:docs/adr/0041-narrow-blanket-notable-exec-corroboration.md if this lands first).

  • Flat arm → false. Behavior::ProcessExec no longer blanket-corroborates in corroborates() (engine/src/engine/reason/proof/corroborate.rs) — it joins PrivilegeChange/PtraceAttach/ModuleLoad as model-evidence-only, restoring the ADR-0011 on-call-engineer (kubectl exec -it … bash) false-positive guard the old blanket arm had suspended for Falco parity.
  • New shape reverse_shell_on_foothold. An is_interactive_shell ProcessExec AND an internet NetworkConnection on the same entry within a symmetric 60s window (|Δt| ≤ 60s over provenance.observed_at, both directions), foothold-gated (entry.is_foothold), corroborating any objective. REVERSE_SHELL_WINDOW sits beside DROP_EXEC_WINDOW.
  • This clears the ADR-0024 "no redundant-by-construction predicates" gate that blocked the shape until the blanket arm narrowed — the shape was stripped once before (see 9620492) for exactly that reason, and lands load-bearing now.

The three divergences applied vs. the recovered pre-strip implementation (git show 9620492^:...)

  1. Keyed on is_interactive_shell ONLY, not the old notable_exec (shell OR package manager) — package managers are excluded because they always egress fetching packages; a real install still corroborates via alarming_write, a no-op package-manager exec stays model evidence.
  2. Symmetric window (|Δt| ≤ 60s, both directions) replacing the old asymmetric duration_since (exec-at-or-before-egress) gate — inverts the old negative test into a new positive (egress_before_the_exec_in_window_is_also_a_reverse_shell), covering the connect-back-then-spawn ordering.
  3. Renamed reverse_shell_shapereverse_shell_on_foothold.

Tests

New sibling file corroborate_reverse_shell_tests.rs (per-shape convention, kept out of corroborate_context_tests.rs):

  • shape-positive (shell + in-window egress corroborates where a bare shell alone would not)
  • bare-shell negative
  • package-manager negative
  • window-expiry negative
  • non-foothold negative
  • symmetric-window positive (egress-before-exec)

corroborate_objective_tests.rs:

  • shell_exec_corroborates_any_objective / package_manager_exec_corroborates_any_objective flipped to assert !corroborates(...) (the flip-proof ADR-0024 requires)
  • updated the anon_inode_exec_does_not_blanket_corroborate comment that referenced a shell path also blanket-corroborating
  • new drift-guard: a notable exec still satisfies observe::alarm_class::is_alarming_now after the narrow

incident/mod_tests.rs:

  • new pin test: Assessment::Attack → Verdict::promotes() == true via IncidentDecision::to_verdict() — the mapping ADR-0041's lane-shift reasoning depends on

corroborate_context_tests.rs: updated the stale doc comment that described the reverse-shell shape's earlier removal.

Commands run

  • cargo fmt
  • cargo check — clean
  • cargo clippy --all-targets -- -D warnings — clean
  • cargo test1221 passed, 0 failed, 2 ignored (pre-existing), including file_size_guard and self_containment_guard

Invariants preserved

  • Ships in audit (shadow default) — Falco's Behavior::Alert arm is unchanged and stays the live corroboration floor while Falco coexists, so this is zero operational recall change today.
  • No PROTECTOR_*_ENABLE toggle, no wire/behavior-crate change, no weak/strong tier.
  • corroborate.rs is 564 lines (< 1000 cap), tests in the sibling file.
  • observe::alarm_class::is_alarming_now, observe::exec_class, incident-menu seeding, and the zero-anchor guard (reason::adjudicate::guards) are untouched (confirmed structurally separate from corroborates(); drift-guard test added).

Closes JEF-393

thejefflarson and others added 2 commits August 6, 2026 19:04
…reverse_shell_on_foothold (ADR-0041)

Behavior::ProcessExec no longer blanket-corroborates via the flat corroborates()
relation — it joins PrivilegeChange/PtraceAttach/ModuleLoad as model-evidence-only,
restoring the ADR-0011 on-call-engineer (kubectl exec -it ... bash) false-positive
guard the old blanket arm had suspended for Falco parity.

What replaces it is a shape, not a wider blanket: reverse_shell_on_foothold
correlates an is_interactive_shell exec with a same-entry internet
NetworkConnection within a symmetric 60s window (covers both exec-then-connect
and connect-back-then-spawn), foothold-gated, corroborating any objective.
Package managers are excluded from the shape (they always egress fetching
packages; a real install still corroborates via alarming_write). This clears
the ADR-0024 redundant-by-construction gate that blocked the shape before the
blanket arm narrowed (see 9620492).

- corroborate.rs: flat arm -> false, REVERSE_SHELL_WINDOW const, the new shape,
  disjunct in corroborated_for, doc-comment rewrites citing ADR-0041/0024/0011.
- corroborate_reverse_shell_tests.rs (new sibling): shape-positive, bare-shell
  negative, pkg-mgr negative, window-expiry negative, non-foothold negative,
  symmetric-window positive (egress-before-exec).
- corroborate_objective_tests.rs: flip shell/pkg-mgr blanket tests to assert
  non-corroboration; drift-guard that a notable exec still satisfies
  observe::alarm_class::is_alarming_now after the narrow.
- corroborate_context_tests.rs: update the stale comment noting the
  reverse-shell shape's prior removal.
- incident/mod_tests.rs: pin Assessment::Attack -> Verdict::promotes() == true,
  the mapping ADR-0041's lane-shift reasoning depends on.

Falco's Behavior::Alert arm is unchanged and stays the live floor while Falco
coexists (audit is the default posture) — zero operational recall change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tests

The two ADR-0041 flip-proof tests now assert `!corroborates(...)`, but their
names still read `..._corroborates_any_objective` — the opposite of what they
pin. Rename to `..._no_longer_corroborates_any_objective` so a future reviewer
can't misread the name as license to reintroduce the blanket notable-exec arm.
Test-only; no behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@thejefflarson
thejefflarson enabled auto-merge (squash) August 7, 2026 02:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant