Skip to content

Post-submission security, vault and installer maintenance - #5

Merged
aXL333 merged 31 commits into
mainfrom
codey/installer-release-readiness
Sep 5, 2026
Merged

aXL333 merged 31 commits into
mainfrom
codey/installer-release-readiness

Conversation

@aXL333

@aXL333 aXL333 commented Jul 23, 2026 •

Copy link
Copy Markdown
Owner

Scope

This draft carries six intentionally post-deadline commits that are not on public main:

  1. 89633d1 — closes the first audit's critical safety/reliability gaps
  2. 866af36 — closes the round-two named bypasses with bypass-focused tests
  3. 40d2ff1 — adds encrypted, opt-in payment-card vault access
  4. 915fdd3 — hardens and completes the maintained installer path
  5. 7770ec3 — verifies the actual pinned Inno compiler engine used in CI
  6. 970782e — closes the seven Round 3 P0 invariant classes and their sibling paths

What changed

  • makes release payload validation whole-tree and manifest-backed, including root files, helper directories, both MV3 extensions, hashes, and runtime verification
  • rejects side-branch, lightweight, mismatched-version, or otherwise unverifiable release tags before signing
  • refuses unsigned SYSTEM Guardian installation, allows the first correctly signed publisher to establish the HKLM root, and prevents publisher-to-path-hash trust downgrade
  • restores verified last-good settings when the primary is missing or unreadable, migrates legacy seal projections, and refuses security subsystem initialisation after unrecoverable tamper
  • replaces filename-derived alert provenance with an explicit host/agent origin and leaves slow UAC launches under the controller's bounded timeout
  • applies payment-card and signup gates across every verb and exact argument, rejects mixed extension references, blocks unknown browser verbs, and redacts Luhn-valid PANs
  • audits decoy writes/deletes, correlates 4660 deletion events, reports armed-versus-expected coverage, revalidates at startup, and reports partial coverage as Attention
  • retains the encrypted payment-card vault UI, human-editable fields, and per-connected-harness opt-in switches
  • retains the maintained per-user installer path and bundled extension loading paths

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-alpha3 at c5fd504 remains unchanged as the immutable Build Week deadline snapshot. This draft is clearly post-submission maintenance: it does not alter the Devpost entry, video, /feedback ID, tag, or existing Releases. No alpha4 tag or release has been created.

Validation

  • isolated dotnet build Foreman.slnx -c Debug: 0 warnings, 0 errors
  • all six suites: 1,426 passed (Core 1,082; MCP 187; Guardian 21; Monitor 84; Vault 45; Linux 7)
  • extension mixed password/card bypass test: passed
  • release-source guard: rejects annotated side-branch and lightweight main tags; accepts the annotated main-line fixture
  • release payload bypass suite: rejects root DLL, hidden/root extras, unknown directories, helper siblings, extension extras, and test fixtures; exact 40-file payload passes
  • workflow YAML and all PowerShell scripts parse successfully
  • git diff --check: clean

Follow-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.md section 9.

aXL333 added 5 commits July 22, 2026 07:48
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.
@aXL333 aXL333 changed the title Post-submission maintenance: payment vault and installer hardening Post-submission security, vault and installer maintenance Jul 23, 2026
aXL333 added 24 commits July 26, 2026 17:58
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.
@aXL333
aXL333 merged commit 877a47f into main Sep 5, 2026
1 check failed

This branch was previously deployed

1 inactive deployment
github-pages — 877a47fd Deployed Sep 5, 2026 by aXL333 via deploy #1
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