Skip to content

Commit af250e7

Browse files
committed
fix(release): strip shipped binaries
Release binaries carried their full symbol table. Production compiles without -g, but the linker keeps .symtab regardless, so every archive shipped ~536 KB of internal function names that nothing needs: a bigger download and a free map of the internals, by accident rather than by decision. Nothing symbolizes at runtime -- mem_profile.c is not in the production build and never calls backtrace_symbols -- so no diagnostics are lost. It also had a concrete cost. Microsoft's ML scored the unstripped linux-amd64 binary Trojan:Script/Wacatac.B!ml (1 engine of 62) and blocked release run 30398064336 at the VirusTotal gate. That verdict is a decision-boundary artifact, not a property of the code, and the evidence is unambiguous: * the dry-run build two days earlier (d587dea) is the same program 10 KB larger and scans CLEAN -- a 0.003% delta flips the verdict * the delta in that window is almost entirely DELETION of Windows-only files that Linux never compiled * the ui build of the same commit was never flagged * two independently flagged builds drew different sub-variants (Wacatac.B and Wacatac.C), which a real signature does not do * v0.9.0, re-analysed against the same engine build, is still clean -- so this is not model drift either Stripping removes the symbol-name feature surface those models score. It cleared BOTH flagged builds, and every other platform stays clean, so this fixes Linux without trading the problem sideways. Verified before merge: linux-amd64 (f440743) stripped 0 malicious / 62 engines linux-amd64 (0802689) stripped 0 malicious / 62 engines linux-arm64 stripped 0 malicious / 61 engines linux-amd64-portable stripped 0 malicious / 62 engines windows-amd64 stripped 0 malicious / 68 engines darwin-arm64 stripped + re-signed 0 malicious / 60 engines macOS needs care and gets it. The build workflow ad-hoc signs BEFORE this script runs, so stripping invalidates that signature and the kernel then refuses to exec the image; Mach-O is re-signed here. It also uses `strip -x` rather than --strip-all, because a full strip can leave an image dyld will not load. The packaged macOS binary verifies (`valid on disk`, `satisfies its Designated Requirement`) and runs, and the full macOS smoke passes against a stripped, re-signed binary. Build fingerprints are derived from the file itself during execution, with nothing embedded during compilation, so staged and target agree and activation is unaffected. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
1 parent f440743 commit af250e7

1 file changed

Lines changed: 49 additions & 0 deletions

File tree

scripts/package-release.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,53 @@ BUILD_DIR="${BUILD_DIR:-build/c}"
9191
OUT_DIR="$(mkdir -p "$OUT_DIR" && cd "$OUT_DIR" && pwd)"
9292
NAME="codebase-memory-mcp${SUFFIX}-${GOOS}-${GOARCH}"
9393

94+
# Ship every release binary stripped. Production already builds without -g, but
95+
# the linker still keeps a ~536 KB .symtab, so releases carried their full
96+
# symbol table to users: bigger downloads and a free map of the internals, with
97+
# nothing gained. Nothing symbolizes at runtime (mem_profile.c is not in the
98+
# production build and never calls backtrace_symbols), so this costs no
99+
# diagnostics.
100+
#
101+
# It also had a concrete cost. Microsoft's ML scored the unstripped linux-amd64
102+
# binary Trojan:Script/Wacatac.B!ml (1 engine of 62) and blocked release run
103+
# 30398064336 at the VirusTotal gate. That verdict is a decision-boundary
104+
# artifact rather than a property of the code -- the dry-run build two days
105+
# earlier is the same program plus 10 KB and scans clean, and the ui build of
106+
# the same commit was never flagged. Stripping removes the symbol surface those
107+
# models score and cleared BOTH flagged builds (Wacatac.B and Wacatac.C)
108+
# without changing what the program does.
109+
#
110+
# macOS is ad-hoc signed by the build workflow BEFORE this script runs, and
111+
# stripping invalidates that signature, so Mach-O is re-signed here. Skipping
112+
# the re-sign ships a binary the kernel refuses to exec.
113+
strip_release_binary() {
114+
local binary="$1"
115+
[ -f "$binary" ] || return 0
116+
local stripped=""
117+
for tool in "${STRIP:-}" llvm-strip strip; do
118+
[ -n "$tool" ] || continue
119+
command -v "$tool" >/dev/null 2>&1 || continue
120+
if [ "$GOOS" = "darwin" ]; then
121+
# -x keeps external symbols: a full strip of a Mach-O can leave an
122+
# image dyld will not load.
123+
"$tool" -x "$binary" 2>/dev/null && stripped="$tool"
124+
else
125+
"$tool" --strip-all "$binary" 2>/dev/null && stripped="$tool"
126+
fi
127+
[ -n "$stripped" ] && break
128+
done
129+
if [ -z "$stripped" ]; then
130+
echo "package-release: no working strip for $binary" >&2
131+
return 1
132+
fi
133+
if [ "$GOOS" = "darwin" ]; then
134+
command -v codesign >/dev/null 2>&1 &&
135+
codesign --sign - --force "$binary" 2>/dev/null
136+
fi
137+
echo "=== package-release: stripped $(basename "$binary") ==="
138+
return 0
139+
}
140+
94141
if [ "$GOOS" = "windows" ]; then
95142
# Windows ships ONE binary, exactly like every other platform. There is no
96143
# launcher stub: a small unsigned PE whose entire job is to verify and
@@ -107,6 +154,7 @@ if [ "$GOOS" = "windows" ]; then
107154
PACK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/cbm-package.XXXXXX")"
108155
trap 'rm -rf "$PACK_DIR"' EXIT
109156
cp "$PAYLOAD" "$PACK_DIR/codebase-memory-mcp.exe"
157+
strip_release_binary "$PACK_DIR/codebase-memory-mcp.exe" || exit 2
110158
cp LICENSE install.ps1 "$PACK_DIR/"
111159
scripts/gen-third-party-notices.sh "$PACK_DIR/THIRD_PARTY_NOTICES.md"
112160
(
@@ -119,6 +167,7 @@ if [ "$GOOS" = "windows" ]; then
119167
else
120168
[ -f "$BUILD_DIR/codebase-memory-mcp" ] ||
121169
{ echo "package-release: build first; missing $BUILD_DIR/codebase-memory-mcp" >&2; exit 2; }
170+
strip_release_binary "$BUILD_DIR/codebase-memory-mcp" || exit 2
122171
cp LICENSE install.sh "$BUILD_DIR/"
123172
scripts/gen-third-party-notices.sh "$BUILD_DIR/THIRD_PARTY_NOTICES.md"
124173
tar -czf "$OUT_DIR/$NAME.tar.gz" -C "$BUILD_DIR" \

0 commit comments

Comments
 (0)