Repository navigation
Post-submission security, vault and installer maintenance - #5
Merged
Merged
Conversation
P0-1: cover primary-seal deletion and all-local-seal deletion after durable prior-seal evidence. P0-2: cover unsigned attacker roots with an HKLM anchor, explicit dev opt-in, and transactional policy rollback. P0-3: cover attacker-minted Critical saturation so host High/Critical arrivals survive both stores. P0-4: cover stuck pre-handshake launches, throwing relaunch callbacks, and UAC single-flight recovery. P0-5: cover MCP-token rotation while refusing to bless a current-only settings edit.
P0-1 invariant: a releasable payload is an exact declared tree. First release builds create and verify a whole-tree hash manifest; upgrades delete controlled payload directories before copying; legitimate source additions must be declared; and missing files, hashes, or local validation dependencies fail the release while manifest-free developer runs remain supported. Sibling coverage: root DLLs, hidden files, unknown directories, helper siblings, and extension extras. P0-2 invariant: SYSTEM Guardian installation accepts only the intended signed Foreman publisher and install root. A first signed install may establish the HKLM root; upgrades must match it without trust downgrade; legitimate uninstall clears it; and unsigned or unverifiable builds fail closed instead of accepting an argv opt-in. Sibling coverage: absent roots, attacker-supplied development flags, and publisher-to-hash downgrade. P0-3 invariant: existing secured settings never become weak defaults because primary data, schema, or Guardian availability changes. First run without recovery still receives defaults; upgrades accept and migrate the retained legacy projection; legitimate saves reseal; and missing, corrupt, slow, or unavailable inputs restore verified last-good state or stop security initialisation. Sibling coverage: primary deletion, unreadable JSON, projection drift, and slow Guardian. P0-4 invariant: retention trust comes from an explicit event origin and a pending UAC launch remains controller-owned until it resolves or times out. First-run host events default safely while MCP reports are explicitly agent-originated; upgrades need no operator migration; legitimate host alerts retain priority; and slow UAC prompts are neither killed nor duplicated. Sibling coverage: filename spoofing and long-pending consent. P0-5 invariant: payment-card release requires explicit approval regardless of verb, argument, or extension route. First run and upgrades preserve the encrypted card store and ACLs; legitimate operator approval still resolves only the exact approved argument; and missing presence, unknown verbs, or mixed references fail closed. Sibling coverage: click verbs, decoy arguments, mixed password/card lists, and unrecognised browser verbs. P0-6 invariant: decoy coverage is never reported healthy unless the expected tripwires are armed, and removal is observable. First run reports armed counts; upgrades revalidate tracked paths; legitimate removal produces an auditable notice; and an absent or partial sidecar reports Attention rather than green. Sibling coverage: 4660 deletion correlation, restart-time loss, partial arming, and duplicate paths. P0-7 invariant: only the exact annotated or signed version tag on main may publish a release. First publication and upgrades use the same ancestry and tag-object guard; legitimate manual publication must select a matching tag/version; and missing or unverifiable source metadata fails before signing. Sibling coverage: side-branch tags, lightweight tags, and free-text version mismatch. Deferred: the P1/P2 items remain explicitly listed in docs/audit-2026-07-25-round3-full.md section 9.
First review conducted against the RUNNING product via its own MCP surface as a connected claude-code harness, rather than by reading source. Findings in section 3 were reproduced by calling the product. Headline results: - scan_repo_for_agent_config, reported in three prior audits, is confirmed live and is worse than the static reads showed. It accepts an arbitrary absolute path from a non-operator harness; it reads paths the caller's own declared fileSystem.deniedPaths forbids (verified against C:\Windows\System32\drivers\etc while get_my_permissions reports C:\Windows\System32\* as denied); and it emits no event at any severity, so the read leaves no trace. That denied list is where the decoy credentials live. - get_audit_route is correctly caller-scoped and refuses cross-harness lookups. Same tool surface, opposite outcome: the invariant holds on the path someone thought about and is absent on its sibling. - Foreman.Core.Tests cannot build. Bitdefender blocks the assembly at write time (MSB3021, then CS2012 "denied"), persisting across Release and Debug, a full obj/bin clean, and after an exclusion was added. 426 tests pass across the other five suites; roughly 1167 remain unverifiable. - Operational: no clean-shutdown path, so every scripted restart forges a "terminated WITHOUT a clean shutdown" Critical; the guardian boot-race notice fires on every launch; the HKCU Run auto-start entry has silently reverted twice. Commits only this document. The remaining working-tree entries are a concurrent Codex session's in-flight work and are deliberately left untouched.
Covers the 28 in-flight companion/coordination entries, the CI and test-runner changes, and live probing of the running instance. Two blocking findings: the new mandated test entrypoint runs on no shell installed on this machine, and Core.Tests remains unbuildable. Two security findings: the unscoped repo coordination read, and scan_repo_for_agent_config for the fifth audit running.
Invoke-DotNetTests.ps1 could never have succeeded on any PowerShell. Its loop variable $projectName collides case-insensitively with the script's own [string[]] $ProjectName parameter, inherits that type constraint, and coerces the project name into a one-element String[]; Join-Path then failed with an opaque ChildPath binding error before the first test ran. Renamed the loop variable to $projectBaseName. Verified: 238/238 in Foreman.McpServer.Tests. pwsh is not installed on every supported dev machine, so the local invocations in CONTRIBUTING, the release checklist, and the PR template now use powershell, which the script supports. CI keeps shell: pwsh and no longer nests a second pwsh -File inside an already-pwsh step. Both workflows now install the SDK from global.json instead of 10.0.x, so the pinned 10.0.400 band and rollForward: latestPatch cannot be contradicted by a runner that fetches a newer feature band. Commits global.json and the script alongside the workflows that reference them, since splitting them would break CI on push.
Research found the working premise was wrong: Defender is not in passive mode, it is fully stopped with engine 0.0.0.0, no signatures, no scheduled tasks and zero AMSI providers, while Bitdefender holds the boot-start ELAM slot. Verified live. The machine has one protecting product, not two, which makes the switch a swap rather than a reduction. The uninstall gate is a procedure, not a TraceBrake feature. Phase 0 is a pre-flight, an elevated go/no-go read of the whole Defender policy hive, a staged offline definition package, a restore point, and a verification pass that includes an EICAR functional test rather than status bits alone. Phases 1-6 give TraceBrake the part Defender cannot do: tying a detection to the agent session that caused it. Eighteen invariants keep it from ever weakening Defender as a side effect, starting with never registering as an antivirus, which on this SKU would turn Defender off.
Harvested from a security product's own attack-chain store before uninstalling it, since the data does not survive removal. Six incidents, 497 process nodes, 292 distinct command lines, nine of which were classified as malware. All nine were Microsoft-signed binaries: powershell.exe, pwsh.exe, csc.exe and VBCSCompiler.exe. av-fp-command-corpus.json is a negative corpus. Every entry is benign, so a detector that fires on one is producing a false positive; the nine flagged entries are the hard cases because a shipping product called them malware. bd-atc-false-positive-corpus.json keeps the full attack graphs for reasoning about how attribution goes wrong across a chain. Redacted and verified: username, SIDs, shell snapshot ids and two unrelated project names. Eleven encoded command blobs were decoded and checked; no credentials or tokens present.
Makes the case for an automation-supervisor software class and a provenance declaration that grants nothing: no exemption, no allowlist, no suppression, no trust. A declaration that could grant something would be a self-service allowlist, which is a malware primitive, so that is treated as disqualifying rather than as a caveat. Vendor-neutral by design. The measured evidence is presented without naming the product, because the argument is about a structural gap rather than a product defect. Centres the thesis on harness output ambiguity: agent tool calls present adversarial form with benign semantics, which inverts the threat model the PowerShell detection literature is built around. Cites Li et al. CCS 2019 for semantic-aware detection and Sophos YaraML for compiling a trained classifier into inspectable rules, which is the basis Project Powersmell adapts. Smallest vendor ask is interdiction transparency, not trust: surface a machine-readable record when a layer interdicts or overrides an exclusion. ERROR_VIRUS_INFECTED and ERROR_VIRUS_DELETED already exist for part of it.
Names the class after structured clearance over 74 candidates, 36 of which survived trademark, product and acronym checks. Class is automation provenance, artifact is an Automation Declaration. No abbreviation is sanctioned anywhere: APD is Attack Path Discovery inside security, and the bare word provenance is claimed by several holders. Rejections recorded because they are traps: delegated execution loses on three independent readings (Kerberos constrained delegation and OAuth on-behalf-of, agent-to-agent handoff, and an authenticated grant of authority), execution provenance is already a funded vendor's protocol name, and both of the previous provisional terms are disqualified, supervision because it implies authority over the supervised party. Repositions the whole paper against Microsoft's shipped work rather than as a proposal into a vacuum. Entra Agent ID is GA and MXC previews container-scoped attribution, so the principle is conceded and the vocabulary exists. The two remaining gaps are what the class names: agents in the developer's own interactive session, which container-scoped identity cannot reach, and the handoff of attribution to endpoint security products. No containers are proposed or reimplemented.
Writes the schema prohibition into conformance rather than leaving it as a design convention, since the safety of the whole format rests on it. Section 5.3 closes the schema and names the forbidden fields permanently: a version introducing action, allow, exempt, trust, suppress or any field expressing a request about consumer behaviour is defined as not a successor to this spec. Separates declarant and consumer conformance so either can be implemented alone. The load-bearing consumer requirement is 5.2.1: a declaration, or its absence, may never be an input to any detection, scoring or blocking decision. A declaration may inform what a human is told, never what a machine does. 5.2.3 forbids treating absence as a negative signal, so the format cannot become coercive against developers who do not publish one. Invalidation is deliberately all-or-nothing. An unknown behaviour token voids the whole declaration rather than degrading gracefully, which would make novel tokens a laundering channel, and under-declaration voids it too, so minimising is worse than over-declaring and the incentive points at honesty by construction rather than by good faith. Published CC0 so a proprietary vendor's counsel can read and implement it without escalation.
41 vectors, all passing against a bundled reference validator, covering every mechanically checkable rule in sections 4 and 5.4. Each vector document contains only the declaration. Facts a consumer learns from its environment (signature verified, hashes matched, behaviour observed, publication scope) live in index.json beside the vector, never inside the document, because section 4.3 forbids a document asserting its own validity. A vector carrying its own verdict would be testing a format that does not exist and would teach implementers the wrong shape. Four expectations rather than a boolean, so the consumer requirements are testable: INVALID means treat as absent rather than weakly credible, VALID_BUT_UNCREDITED covers per-user scope under 5.2.5, and ABSENT covers 5.2.3, that absence must never be a negative signal. Adds section 4.7 to the spec, rejecting control characters and bidirectional overrides at parse. A bidi override lets a purpose string render opposite to what it declares, which defeats a document whose entire value is human review. Also states that the document size limit is the backstop for arrays with no count bound of their own, and records the two requirements no vector can test: 5.2.1 and 5.2.3 are structural properties of a consumer, checkable only by inspection.
…tion The working folder moved from W:\TOOLS\Foreman to T:\TOOLS\Foreman. T: was ten commits behind and carried a partial drive-letter rewrite but no unique content; that was verified by hashing both trees and confirming every file on T: either matched W: or existed in W:'s history. A rollback branch, pre-migration-snapshot-2026-09-05, holds T:'s prior working tree. Rewrites thirteen references across four operational files: live trigger paths, a polling script, an automation prefill config, and an implementation spec. Deliberately NOT rewritten, because changing them would falsify a record: the antivirus false-positive corpus under tests/fixtures/av-corpus/, which contains the literal paths a security product logged; dated audit and review documents quoting real error output; and the synthetic fixtures in Startup*Tests.cs, where the drive letter carries no meaning beyond "not the system drive" and which could not be executed to verify a change. Also closes open question 1 in the Defender cutover plan, and records that the antivirus exclusion must now name T:\TOOLS\Foreman.
The repository was renamed to aXL333/TraceBrake, but the generated release note
and the release checklist both told users to run
`gh attestation verify --repo aXL333/Foreman`. GitHub still redirects the old
name, so this looked fine, but an attestation binds to the repository recorded
in its certificate at build time, and verifying against a stale name is not
something to leave to a redirect.
release.yml now generates the line from ${{ github.repository }} rather than a
literal, matching what the explanatory comment twelve lines below it already
used. That cannot go stale on a future rename. The checklist hardcodes the
current name, since a workflow expression is not available in markdown, and
explains why the old name still appears to work.
Also corrects the repository URL in the whitepaper and in the specification's
contactUri example, both authored before the rename was noticed.
Left alone deliberately: the old name in the antivirus corpus and in the
2026-07-25 audit, where it is part of a captured record rather than a live
reference.
This branch was previously deployed
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.
Scope
This draft carries six intentionally post-deadline commits that are not on public
main:89633d1— closes the first audit's critical safety/reliability gaps866af36— closes the round-two named bypasses with bypass-focused tests40d2ff1— adds encrypted, opt-in payment-card vault access915fdd3— hardens and completes the maintained installer path7770ec3— verifies the actual pinned Inno compiler engine used in CI970782e— closes the seven Round 3 P0 invariant classes and their sibling pathsWhat changed
Root cause
Round 2 fixed the paths named by the previous report but did not consistently enforce the security properties around them. Round 3 therefore treats each issue as an invariant over every attacker-influenceable input and tests deletion, absence, alternate verbs/arguments, spoofed provenance, slow dependencies, first install, upgrade, and operator-driven paths.
Build Week boundary
v0.1.0-alpha3atc5fd504remains unchanged as the immutable Build Week deadline snapshot. This draft is clearly post-submission maintenance: it does not alter the Devpost entry, video,/feedbackID, tag, or existing Releases. Noalpha4tag or release has been created.Validation
dotnet build Foreman.slnx -c Debug: 0 warnings, 0 errorsgit diff --check: cleanFollow-up before public release
Keep this PR draft while Round 3 receives adversarial verification. Before any public maintenance prerelease: obtain a signing certificate for Guardian, smoke-test clean install and alpha3 upgrade on a disposable Windows VM, test partial/missing decoy coverage, load and pair both extensions, and verify uninstall cleanup. Then review the explicitly deferred P1/P2 list in
docs/audit-2026-07-25-round3-full.mdsection 9.