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
Conversation
…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
enabled auto-merge (squash)
August 7, 2026 02:48
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements ADR-0041 (narrow the blanket notable-exec corroboration arm to shapes; PR #328, not yet on
main— read fromorigin/corroboration-floor-narrowing:docs/adr/0041-narrow-blanket-notable-exec-corroboration.mdif this lands first).false.Behavior::ProcessExecno longer blanket-corroborates incorroborates()(engine/src/engine/reason/proof/corroborate.rs) — it joinsPrivilegeChange/PtraceAttach/ModuleLoadas 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.reverse_shell_on_foothold. Anis_interactive_shellProcessExecAND aninternetNetworkConnectionon the same entry within a symmetric 60s window (|Δt| ≤ 60soverprovenance.observed_at, both directions), foothold-gated (entry.is_foothold), corroborating any objective.REVERSE_SHELL_WINDOWsits besideDROP_EXEC_WINDOW.9620492) for exactly that reason, and lands load-bearing now.The three divergences applied vs. the recovered pre-strip implementation (
git show 9620492^:...)is_interactive_shellONLY, not the oldnotable_exec(shell OR package manager) — package managers are excluded because they always egress fetching packages; a real install still corroborates viaalarming_write, a no-op package-manager exec stays model evidence.|Δt| ≤ 60s, both directions) replacing the old asymmetricduration_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.reverse_shell_shape→reverse_shell_on_foothold.Tests
New sibling file
corroborate_reverse_shell_tests.rs(per-shape convention, kept out ofcorroborate_context_tests.rs):corroborate_objective_tests.rs:shell_exec_corroborates_any_objective/package_manager_exec_corroborates_any_objectiveflipped to assert!corroborates(...)(the flip-proof ADR-0024 requires)anon_inode_exec_does_not_blanket_corroboratecomment that referenced a shell path also blanket-corroboratingobserve::alarm_class::is_alarming_nowafter the narrowincident/mod_tests.rs:Assessment::Attack → Verdict::promotes() == trueviaIncidentDecision::to_verdict()— the mapping ADR-0041's lane-shift reasoning depends oncorroborate_context_tests.rs: updated the stale doc comment that described the reverse-shell shape's earlier removal.Commands run
cargo fmtcargo check— cleancargo clippy --all-targets -- -D warnings— cleancargo test— 1221 passed, 0 failed, 2 ignored (pre-existing), includingfile_size_guardandself_containment_guardInvariants preserved
audit(shadow default) — Falco'sBehavior::Alertarm is unchanged and stays the live corroboration floor while Falco coexists, so this is zero operational recall change today.PROTECTOR_*_ENABLEtoggle, no wire/behavior-crate change, no weak/strong tier.corroborate.rsis 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 fromcorroborates(); drift-guard test added).Closes JEF-393