Skip to content

harden(cli): stop shipping a policy-bypass invocation inside the binary - #1492

Merged
DeusData merged 2 commits into
mainfrom
harden/av-surface-strings
Aug 7, 2026
Merged

DeusData merged 2 commits into
mainfrom
harden/av-surface-strings

Conversation

@DeusData

@DeusData DeusData commented Aug 7, 2026

Copy link
Copy Markdown
Owner

cbm update printed the Windows update command with an execution-policy override baked in as a string literal, putting one of the most heavily weighted malicious-script patterns inside every Windows artifact we distribute — to save the user a single documented step.

What changes

The command prints without it. Functionality is unchanged:

  • the user still gets a runnable command
  • the failure it was pre-empting (PowerShell refusing a file that came from the internet) is answered by Unblock-File, which the message now names explicitly
  • the restricted-policy case lives in the README's Windows install section, which already documents it

Documentation is the right home for that incantation; a shipped binary is not.

Scope — deliberately not oversold

The 2026-08-07 dry-run detections are NOT attributable to this string. It is #ifdef _WIN32, and every Windows artifact scanned clean; the three flagged artifacts were Linux and macOS. This is margin hygiene.

For the record, that investigation reached a definitive negative result: every flagged artifact has a clean UI counterpart on the same platform and arch, built from identical sources in the same run — and the UI binary is a strict superset. No code passage in the standard binary can be the trigger, because the superset containing all of them scans clean. The detection is a marginal !ml score on a zero-prevalence unsigned binary.

Verification, including its limit

make lint-ci clean; cli suite 261 passed. Source verified free of the literal outside comments.

The built-artifact check is vacuous on a non-Windows host — the literal was Windows-only, so a macOS build shows zero occurrences with or without this change. A real artifact check needs the Windows build leg, which CI provides.

`cbm update` printed the Windows update command with an execution-policy
override baked in as a string literal. That put one of the most heavily
weighted malicious-script patterns there is inside every Windows artifact we
distribute — to save the user a single documented step.

The command now prints without it. Functionality is unchanged: the user still
gets a runnable command, and the failure it was pre-empting (PowerShell refusing
a file that arrived from the internet) is answered by Unblock-File, which the
message now names. The restricted-policy case is documented in the README's
Windows install section, which is the right home for that incantation — a
shipped binary is not.

Scope note, so this is not oversold: the 2026-08-07 dry-run detections are NOT
attributable to this string. It is `#ifdef _WIN32`, and every Windows artifact
scanned clean; the three flagged artifacts were Linux and macOS. This is margin
hygiene, not a fix for that regression — see the analysis in the PR.

Verification limit worth stating: the built-artifact check for this string is
vacuous on a non-Windows host, since the literal was Windows-only to begin with.
What is verified here is the source (no occurrence outside a comment) plus lint
and the cli suite; a real artifact check needs the Windows build leg in CI.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The contract asserted the literal "powershell -ExecutionPolicy Bypass -File"
appeared in cbm_cmd_update, so removing that string from the binary reddened
every test leg on every platform — the contracts run as step 0 of scripts/test.sh,
so one violation stops the matrix before a single suite executes. 13 checks, one
cause.

The contract's stated intent is that the Windows update command "must hand off to
install.ps1 and must NOT carry an in-process self-update path". The bypass flag
was never that property, only the literal form the command happened to take. The
assertion now pins the hand-off itself ("powershell -File" plus install.ps1),
which is what the comment always claimed to protect.

Adds the inverse assertion in the same place: the printed command must NOT
contain an execution-policy override at all. Without it this contract would
silently permit the pattern coming back, and the whole point of removing it was
that a shipped binary is the wrong place to carry a canonical loader signature.

Process note for myself: I ran the cli suite and lint before pushing, but not the
contracts — which is precisely the gap recorded as "scripts/test.sh runs them as
step zero of EVERY leg, so one violation reddens all 30 CI jobs". Ran the full
contract set this time.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
@DeusData
DeusData enabled auto-merge August 7, 2026 20:00
@DeusData
DeusData merged commit 6a1ef1e into main Aug 7, 2026
33 checks passed
thientrile pushed a commit to thientrile/codebase-memory-mcp that referenced this pull request Aug 10, 2026
Externalizing the integration templates (DeusData#1492/DeusData#1493) and the UI bundle
(DeusData#1501/DeusData#1503) was done to reduce the Microsoft `Wacatac.B!ml` surface. It did
not work: across dry runs the flagged artifact count stayed at ~3 and the
detections merely moved between artifacts.

Dissection of run 31286803592 shows there is no structural cause to fix. The
verdicts split across every axis at once — linux-amd64 (dynamic) flagged while
linux-amd64-portable (static) is clean, but linux-arm64 (dynamic) clean while
linux-arm64-portable (static) is flagged. The two macOS binaries have identical
segment structure and split clean/flagged. Siblings from one build landed in
different variant buckets (.B vs .C). Entropy is low everywhere
(code_vectors.bin 4.166, grammar tables 3.464 bits/byte, against 7.5-8.0 for
packed payloads), so the packed-payload hypothesis is excluded too.

So the complexity bought nothing, and installation goes back to being
self-contained: one binary that carries its own UI and agent integration
templates, with no adjacent data file that has to resolve before `install`
works. Only the UI-capable composition ships from now on, under the historical
unsuffixed archive name.

Removed: src/ui/asset_pack.{c,h}, asset_pack_stub.c, asset_manifest_stub.c,
scripts/pack-ui-assets.mjs, src/cli/integration_assets.{c,h},
assets/cbm-integrations.json, scripts/gen-integrations-hash.sh, the
--verify-runtime-assets probe (nothing adjacent left to verify), and the
composition gates A6/A7 whose property is now deliberately inverted.

Restored: scripts/embed-frontend.sh, src/ui/embedded_{assets.h,stub.c}, the
compiled-in hook/adapter template bodies, and the embed/EMBED_OBJS build path.

Kept from the reverted commits, re-applied by hand where a wholesale file
restore would have dropped them:
  - cbm_module_path_utf8() in both self-path sites. GetModuleFileNameA renders
    through the ANSI code page and mangles non-ASCII install paths.
  - the /__cbm/ui-readiness HMAC proof, secure_random and cbm_hmac_sha256, so
    `daemon start --open` still waits for a genuine CBM listener.
  - X-Content-Type-Options: nosniff on served assets.
  - the MinGW noexecstack gate, -lbcrypt, and the cppcheck/zip CI fixes.

Archives are now codebase-memory-mcp-<os>-<arch>[-portable] with exactly four
members (binary, LICENSE, installer, THIRD_PARTY_NOTICES.md). That restores the
names every static package manifest already points at — aur, chocolatey,
homebrew, scoop, winget and glama were all broken by the -ui- rename.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
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