Repository navigation
#352: the beacon sensor graded a supervised Worker as if nobody had started it - #68
Merged
opencdlee-dotcom merged 1 commit intoSep 24, 2026
Conversation
#352: a Runner.Worker's "Persistent outbound connection (beacon shape)", HIGH with no rung, while the process sensor graded the same bytes `supervised` in the same scan. check_processes handed _grade_binary the ancestor exe list; the network sensors never did, and _outbound_rows dropped the pid that would have let them. _parents_by_pid is now the one spelling of "who started this pid" for all three sensors: _ancestry's walk (pid-reuse guard included), the ancestry table built at most once and only on the first pid actually asked about, and never on a host with no vouch. _outbound_rows keeps the pid; both beacon emitters and _outbound_findings pass `parents` and record `ancestry` (exe paths); the pid is kept beside the stored beacon history, never in it. The replay now reads recorded ancestry for net-beacon and net-outbound as it does for process, so a beacon without it where a vouched program could have earned the rung is counted `field missing: ancestry`. The listener is not wired: its snapshot is keyed path:port and drops the pid by design. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
opencdlee-dotcom
merged commit Sep 24, 2026
81f48e6
into
agent/fable-precision/assembly
8 of 9 checks passed
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.
#352: "Persistent outbound connection (beacon shape)" was HIGH with no rung on
~/actions-runners/professor-os/bin.2.336.0/Runner.Worker. In the same scan, the process sensor graded those same bytessupervised.Cause
check_processespasses_grade_binarythe ancestor exe list, so the process sensor sees that the operator-vouched Runner.Listener started the Worker from its own install directory.parents, and_outbound_rowsthrew away the pid that would have let them.ancestry, so the replay could not re-derive the grade either.Change
_parents_by_pid(exe_by_pid=None)is now the one place that answers "who started this pid", used by all three sensors. It reuses_ancestryand its pid-reuse guard. It builds the ancestry table at most once, only when a pid is actually asked about. On a host with no vouch (or a tampered vouch store) it answers[]and never reads the process table.check_processesnow calls it too; its behaviour is unchanged._outbound_rowsreturns(path, ip, port, pid)on all three platforms.check_outboundkeeps the pids beside the rows, never in them. The stored beacon history stays(path, ip, port, trust), because a pid would turn every restart into a new row. It passes anancestry(path, ip, port)lookup to_outbound_findingsand_beacon_recurrence._outbound_findings:parentsto_grade_binary;ancestry(exe paths) on the finding when it is non-empty;parentsto_class_facts, as the process sensor does._outbound_findingsnever called_class_factsand still does not._reobservenow reads recorded ancestry fornet-beaconandnet-outbound(_REOBSERVE_ANCESTRY_CATEGORIES), not only forprocess. A beacon record without ancestry, where a vouched program could have earned it the rung, is countedfield missing: ancestryinstead of being graded as if nobody started it.diff_listenersgrades through_grade_binarywithoutparents, but its snapshot is keyedpath:portand drops the pid by design, so that a restart is not a new listener. Wiring it would need a pid side-channel out of three platform snapshotters. No case in the corpus needs it: the Worker does not listen, and the Listener is vouched itself.Tests (
tests/test_beacon_parents.py, written first; 8 of 9 failed before the change)These drive the real
check_outboundover a fixed process, ancestry and outbound table.supervised, outbound LOWsupervised, andancestry == [Listener].ancestryfield.supervised; a record without it is replayed as recorded withfield missing: ancestry.Verification (this Mac)
2 failed, 2471 passed, 6 skipped, 30 xfailed, 83 subtests passed in 1221.46s. Tree hashes matched before and after the run. Both failures are pre-existing on the assembly base: they fail the same way on an untouchedgit archive 19e6608.TestHostileArgsSeverity::test_benign_interpreter_agent_stays_lowTestExpandedHostileArgs::test_benign_args_stay_low'INFO' != 'LOW'for a/bin/echolaunchd job. That is persistence grading, which this change does not touch.backtest replay --days 30 --reobserve, run concurrently on one snapshot (62,799 events, 214 noise-labelled), 19e6608 vs this branch:#352 #382 #432 #452), as recorded 50. After: re-derived 3 (#382 #432 #452), as recorded 51.#352is nowas recorded · field missing: ancestry, and that reason covers 6 incidents:#289 #290 #351 #352 #384 #534.ancestry. Example:net-beacon LOW operator-vouchedforprofessor-os/bin/Runner.Listenerhas ancestry['./externals/node20/bin/node', '/bin/bash', '/sbin/launchd'], and the VS Code extension beacons carry their Code Helper chain.🤖 Generated with Claude Code