Skip to content

v2.1.35 — Correction

Choose a tag to compare

@agent-kay-it agent-kay-it released this 10 Aug 15:03
· 29 commits to main since this release
3352f26

bkit v2.1.35 — Correction

An outside contributor sent a one-file security hardening patch. Reproducing its
claim found that the vulnerability it reported was not reachable — and that two
real defects had been shipping in that same file since v2.1.12, one of which had
bkit telling users, in writing, something about Claude Code that is not true.

This release is what happens when you measure a patch instead of merging it.


Highlights

bkit told you its hooks might not work in a git worktree. They work.

Until this release, starting bkit inside a linked worktree printed:

git worktree detected — Claude Code hooks may not fire (issue #46808). Run bkit from the primary repository if hook-driven automation is required.

Nobody had ever measured that. We did, with a matched control — one live
claude -p --plugin-dir session inside a linked worktree, one in the primary
checkout of the same repository, both read back from bkit's own dispatch ledger:

linked worktree primary checkout
hook events dispatched SessionStart, InstructionsLoaded, UserPromptSubmit, Stop, SessionEnd identical set

The hooks are not degraded in any observable way. The issue the advisory cited,
anthropics/claude-code#46808,
is closed as not planned, and it is about project-level
.claude/settings.json — a different configuration source from the plugin
hooks/hooks.json that bkit actually ships.

Detection stays, because a worktree really can be missing project-scope
.claude/ configuration when that directory is untracked or gitignored. What is
gone is the claim about bkit's own hooks, the citation of a declined issue as a
live defect, and the advice to leave your worktree.

A subdirectory of an ordinary checkout was reported as a worktree

git rev-parse --git-dir answers with an absolute path. --git-common-dir
answers relative to the current working directory. bkit resolved both against
the repository toplevel — the wrong base — so from repo/sub/deep it compared
/repo/.git against /repo/../../.git and concluded you were in a worktree.
Symlinked checkouts (/tmp/private/tmp on macOS) failed the same way.

Detection now asks git for absolute paths directly and compares through
realpath. Verified across 8 topologies with zero mismatches, and both
superseded implementations are re-implemented inside the test suite as a negative
control — so the suite provably fails if either one returns.

Every child_process call in shipped code passes an argv array

PR #146 converted one call site. Seven remained, two of which interpolated
variables into a shell string: a remote name parsed out of your own git push,
and a GitHub handle inside a quoted search expression. Neither was exploitable,
and both are now argv — with a -- separator so a leading-dash remote name
cannot be read as a flag.

This was already the project's policy; it had just never been enforced. A
contract test now enforces it mechanically, and Claude Code version detection
went from three implementations (two of them shelling out) to one.


What changes for you

Before After
Starting bkit from a subdirectory printed a worktree warning and left a stray flag file behind No warning — a plain checkout is recognized as one
Working in a git worktree told you hooks "may not fire" and to go back to the main checkout You're told what is actually at risk — project-scope .claude/ config — and that bkit's own hooks are unaffected, with the Claude Code version the claim was measured against recorded in the flag file
The warning cited an issue that had been declined, as though it were live The advisory cites only what currently reproduces
Nothing else visible Nothing else changes. No commands, skills, agents, or state formats moved.

Upgrading is a drop-in: claude plugin update bkit. There are no migrations and
no configuration changes.


For maintainers

Three defects in this release were found by running things, not reading them, and
all three are the same shape — a claim nobody re-measured:

  • The worktree advisory asserted a behavior of Claude Code that had never
    been tested and had stopped being true.
  • A quality gate could fail because bkit was running. SB-011 compared two
    reads of the developer's live .bkit/state/ taken ~80 lines apart, and a bkit
    session in the same repository rewrites trust-profile.json between them.
    Observed as control: 38, engine: 50, passing on the next run. Both readings
    now come from one child process pinned to an empty CLAUDE_PROJECT_DIR
    deterministic on a fresh clone, on a dogfooding machine, and in CI.
  • The test runner listed four files it could not find, and counted them as
    skips.
    v2.1.16's stale-test cleanup deleted the files and left the manifest
    entries. For 19 releases the generated report printed them under Failures
    while the verdict counted them as skips — a report that listed failures it did
    not count. Fixed, and a contract test now fails if the manifest and the
    filesystem ever disagree again.

WorktreeCreate / WorktreeRemove registration stays deferred on the reasoning
recorded in v2.1.33 (ENH-396/418): confirmed supported by Claude Code, deferred
for the hook-count cascade. This release removes an incorrect claim about
worktrees; it does not add worktree lifecycle management.

ENH: 424–431.


Credits

@anupammePR #146.
A one-file execSyncexecFileSync hardening patch that, on reproduction,
turned into this release. The migration is theirs and now covers the whole
repository.

The semgrep finding behind it (javascript.lang.security.detect-child-process,
HIGH) is a true description of the pattern and a false description of the risk at
that call site — all three callers passed module-internal literals. We kept and
extended the migration anyway, because removing the shell means a future caller
cannot reintroduce the primitive. That is the useful half of a scanner finding
that did not reproduce.