You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Capture.sh's header documents its exit codes as 0 ok; 2 bad args; 3 preflight failed (propagated); 7 target denied. Nothing is propagated. The
call site runs the gate inside if ! … and returns a constant — and the comment directly above it
states the contract a second time, in the same file, one line before the code that breaks it:
# --- 2. hardened preflight gate (propagate its exit + stderr verbatim) ---if! bash "$SCRIPT_DIR/PreflightIsolation.sh">&2;then# Preflight already printed structured remediation. Do not try anyway.exit 3
fi
PreflightIsolation.sh distinguishes eight failure classes by exit code — 2 binary missing,
3 version-parse, 4 version too low, 5 nothing connected, 6 pinned context not connected, 7 target is
a denied profile, 8 test context unset, 9 no pinned Extension. All eight arrive at a Capture.sh
caller as 3. A caller cannot tell "you targeted a denied profile" (a refusal it must not retry)
from "re-pin the extension" (a fixable local state) from "the binary is missing".
Capture.sh also reuses 3 for an unrelated condition of its own — the pinned context missing from
the live connected set at :176 — so the code is overloaded inside the file as well as against the
header. The gate's stderr is passed through, so a human reading the terminal sees the real reason;
a script branching on the status code cannot.
The header's own words are the contract this contradicts: "structured remediation to stderr,
distinct non-zero exit per failure class."
Header, in-file comment and implementation disagree:
# Three different preflight failure classes, driven through both scripts. A stub# `interceptor` satisfies the binary and connection checks; HOME is redirected so# no real preferences file is read.
git clone --branch v7.40.4 --depth 1 https://github.com/danielmiessler/LifeOS.git /tmp/lifeos-7404
cd /tmp/lifeos-7404 && git rev-parse HEAD
# → be9e8ef889f00a29f4fd677dee4772fdf32e07ce
mkdir -p /tmp/cap/bin /tmp/cap/home /tmp/cap/ext
printf'{"version":"1.0.0"}\n'> /tmp/cap/ext/manifest.json
cat > /tmp/cap/bin/interceptor <<'STUB'#!/usr/bin/env bashcase "$1" in --version) echo "interceptor 0.16.9 (deadbee, 2026-08-14)" ;; contexts) echo "[stub] → contexts"; echo "$STUB_CONTEXTS" ;; *) exit 1 ;;esacSTUB
chmod +x /tmp/cap/bin/interceptor
D=/tmp/lifeos-7404/LifeOS/install/skills/Interceptor/Tools
probe() { # label live-ctx pinned-ctx deny-list ext-dir
env -i HOME=/tmp/cap/home PATH=/tmp/cap/bin:/usr/bin:/bin STUB_CONTEXTS="$2" \
INTERCEPTOR_TEST_CONTEXT_ID="$3" INTERCEPTOR_WORKING_PROFILE_IDS="$4" \
INTERCEPTOR_EXT_DIR="$5" bash "$D/PreflightIsolation.sh">/dev/null 2>&1; p=$?
env -i HOME=/tmp/cap/home PATH=/tmp/cap/bin:/usr/bin:/bin STUB_CONTEXTS="$2" \
INTERCEPTOR_TEST_CONTEXT_ID="$3" INTERCEPTOR_WORKING_PROFILE_IDS="$4" \
INTERCEPTOR_EXT_DIR="$5" bash "$D/Capture.sh""https://example.com">/dev/null 2>&1; c=$?printf'%-32s preflight=%-2s Capture.sh=%-2s\n'"$1""$p""$c"
}
probe "target denied"'ctx-a-9''ctx-a-9''ctx-a-9' /tmp/cap/ext
probe "pinned ctx not connected"'ctx-live''ctx-stale''' /tmp/cap/ext
probe "no Extension at all"'ctx-a''ctx-a''' /tmp/cap/nope
# → target denied preflight=7 Capture.sh=3# → pinned ctx not connected preflight=6 Capture.sh=3# → no Extension at all preflight=9 Capture.sh=3
Negative control
The left column of that same table is the control, and it is red without reference to any fix: the
three distinct codes exist and the gate emits them on the same three runs, so 3 is not the
only value available — it is a value chosen after a more specific one was produced and discarded.
The security-relevant class is the first row: a refusal the caller must never retry is delivered
under the same code as a re-pin-and-try-again condition.
Capture.sh propagates its own codes normally, so the collapse is specific to this call site and
not a limitation of the script:
That makes the header's "(propagated)" true and costs one line. It does collide with Capture.sh's
own use of 3 at :176 and its own 7, so if you would rather keep Capture.sh's codes
independent, the alternative is an offset (say 20 + preflight_status) documented in the header.
Either way the header and the code should agree; today they do not, and the header is the part
callers read.
The repro runs against a clean tree of the version above, not against my modified install.
Fresh --depth 1 clone of v7.40.4, HOME redirected, stub binary on PATH.
I removed personal data from the pasted output — real names, absolute home paths, tokens, my
own content. Paths are /tmp/...; every context id is synthetic.
Version
LifeOS 7.40.4 / Interceptor
What is broken
Capture.sh's header documents its exit codes as0 ok; 2 bad args; 3 preflight failed (propagated); 7 target denied. Nothing is propagated. Thecall site runs the gate inside
if ! …and returns a constant — and the comment directly above itstates the contract a second time, in the same file, one line before the code that breaks it:
PreflightIsolation.shdistinguishes eight failure classes by exit code — 2 binary missing,3 version-parse, 4 version too low, 5 nothing connected, 6 pinned context not connected, 7 target is
a denied profile, 8 test context unset, 9 no pinned Extension. All eight arrive at a
Capture.shcaller as
3. A caller cannot tell "you targeted a denied profile" (a refusal it must not retry)from "re-pin the extension" (a fixable local state) from "the binary is missing".
Capture.shalso reuses3for an unrelated condition of its own — the pinned context missing fromthe live connected set at
:176— so the code is overloaded inside the file as well as against theheader. The gate's stderr is passed through, so a human reading the terminal sees the real reason;
a script branching on the status code cannot.
The header's own words are the contract this contradicts: "structured remediation to stderr,
distinct non-zero exit per failure class."
Header, in-file comment and implementation disagree:
LifeOS/install/skills/Interceptor/Tools/Capture.sh:21—# Exit codes: 0 ok; 2 bad args; 3 preflight failed (propagated); 7 target deniedLifeOS/install/skills/Interceptor/Tools/Capture.sh:130—# --- 2. hardened preflight gate (propagate its exit + stderr verbatim) ---LifeOS/install/skills/Interceptor/Tools/Capture.sh:131-133— theif ! bash …PreflightIsolation.sh; then … exit 3; fiblockLifeOS/install/skills/Interceptor/Tools/Capture.sh:176LifeOS/install/skills/Interceptor/Tools/PreflightIsolation.sh:36-39(documented) and theirexitsites throughout that fileWhere (file:line)
LifeOS/install/skills/Interceptor/Tools/Capture.sh:133Repro on a clean tree
Negative control
The left column of that same table is the control, and it is red without reference to any fix: the
three distinct codes exist and the gate emits them on the same three runs, so
3is not theonly value available — it is a value chosen after a more specific one was produced and discarded.
The security-relevant class is the first row: a refusal the caller must never retry is delivered
under the same code as a re-pin-and-try-again condition.
Capture.shpropagates its own codes normally, so the collapse is specific to this call site andnot a limitation of the script:
Suggested fix
Shape only, untested: capture the gate's status and re-exit with it —
That makes the header's "(propagated)" true and costs one line. It does collide with
Capture.sh'sown use of
3at:176and its own7, so if you would rather keepCapture.sh's codesindependent, the alternative is an offset (say
20 + preflight_status) documented in the header.Either way the header and the code should agree; today they do not, and the header is the part
callers read.
Before submitting
Searched
Capture.sh,Capture.sh exit,Interceptor preflight isolation. The Interceptorissues I found — Doctor.ts's Interceptor check reads the wrong preferences.env path and regex, reporting a working setup as broken #1775, Interceptor skill: four defects in the shipped tools, all reproducible on a current install #1802, Capture.sh defaults every verification screenshot to the user's Downloads root, contradicting the hook that forces raw captures to /tmp (follow-up to #1566) #1892, Interceptor SKILL.md documents a Capture.sh 'guarded auto-rebind' that does not exist, and a name-vs-UUID durability distinction the extension does not make #2010, Interceptor Capture.sh recovery runs
pkill -f interceptor-daemon, which also kills Chrome's per-profile relay daemon #2011, Interceptor Capture.sh misclassifies a minimized test window as a daemon wedge; SKILL.md says DOM-render needs no visible window #2013, Capture.sh passes --out tointerceptor screenshot, a flag only the maintainer's patched binary accepts — every capture fails with exit 9 on a stock install #2065 — cover other tools andother defects; Interceptor SKILL.md documents a Capture.sh 'guarded auto-rebind' that does not exist, and a name-vs-UUID durability distinction the extension does not make #2010 concerns a documented auto-rebind that does not exist and Interceptor Capture.sh misclassifies a minimized test window as a daemon wedge; SKILL.md says DOM-render needs no visible window #2013 a
misclassified minimized window. None reports the exit-code contract. That list is what I
found, not a claim of completeness — a title search for "Interceptor" alone returns 14.
Fresh
--depth 1clone ofv7.40.4,HOMEredirected, stub binary onPATH.own content. Paths are
/tmp/...; every context id is synthetic.