Skip to content

Fix bare-verb severity tier + line locator for bunx / npm exec / yarn dlx#46

Merged
Conalh merged 1 commit into
mainfrom
bare-verb-severity-and-line-locator
May 22, 2026
Merged

Fix bare-verb severity tier + line locator for bunx / npm exec / yarn dlx#46
Conalh merged 1 commit into
mainfrom
bare-verb-severity-and-line-locator

Conversation

@Conalh
Copy link
Copy Markdown
Owner

@Conalh Conalh commented May 22, 2026

Summary

Two follow-up bugs from the previous bare-verb and bunx work. Both surfaced in a reinspection; one of the inspector's proposed fixes was structurally broken and is corrected here.

Bug 1 — Bare Bash/Write/Edit got medium severity instead of high

isBroadAllow was fixed in the prior PR to flag bare "Bash"/"Read"/"Write"/"Edit" as broad, but severityForAllow still matched bash(, write(, edit( with the opening paren. So bare "Bash" — unlimited shell execution — got medium severity instead of high. Switched to a \b(bash|write|edit)\b word-boundary regex.

read deliberately stays at medium (bare and scoped). Read access is less destructive than execute/modify; that asymmetry is intentional, not a bug.

Bug 2 — Line locator never updated for modern runners

lineForUnpinnedCommand still only mapped npx/uvx/pipx. bunx and the wrapper runners (npm exec, yarn dlx, pnpm dlx) were added to isUnpinnedCommand in prior PRs but the locator was left behind — those findings fell back to the server-declaration line instead of pointing at the unpinned package.

Inspector's proposed fix put npm/yarn/pnpm in the same branch as npx. That's brokenlooksLikePackageName('exec') and looksLikePackageName('dlx') both return true, so a naive scan mis-locates to the subcommand line. Verified empirically:

exec   looksLikePackageName: true   hasExactVersion: false
dlx    looksLikePackageName: true   hasExactVersion: false

Correct fix: bunx joins the direct-runner branch (package in args[0..]). npm/yarn/pnpm get their own branch that calls slice(1) to skip the subcommand, gated on the subcommand being a recognized executor (npm exec/x, yarn dlx, pnpm dlx/exec/x).

Test plan

  • npm test — 54/54 passing locally (up from 52)
  • New regression test: bare Bash/Write/Edit get high, bare Read stays medium (locks the asymmetry)
  • New regression test: hand-written .mcp.json with known line numbers asserts bunx + npm exec + yarn dlx all locate to the package line, not the subcommand line
  • CI green

Not in this PR

.aider.conf.yml, .cursorrules, .windsurfrules detection — same as the previous inspection, already filed as #42, #43, #44.

🤖 Generated with Claude Code

Two follow-up bugs from the previous bare-verb / bunx fixes:

1. `severityForAllow` matched `bash(`, `write(`, `edit(` literally,
   requiring the opening paren. Bare `"Bash"` — which the previous
   security fix correctly added to the broad-allow finding — silently
   dropped to `medium` severity despite granting unlimited shell
   execution. Switch to a `\b(bash|write|edit)\b` word-boundary regex
   so bare verbs and parenthesized scopes are both `high`.

   `read` deliberately stays out of the high tier: a bare `"Read"`
   token is still flagged as a finding, just at `medium`, because
   read access is less destructive than execute/modify. That
   asymmetry is intentional.

2. `lineForUnpinnedCommand` only mapped npx/uvx/pipx to the
   args-scan locator. `bunx` (added to `isUnpinnedCommand` in
   fb56768) and the wrapper runners npm/yarn/pnpm (added in 3f44e1e)
   were missing — their findings fell back to the server declaration
   line instead of pointing at the unpinned package.

   `bunx` is a direct runner like npx (package in args[0..]), so it
   joins that branch directly.

   `npm`/`yarn`/`pnpm` are wrappers: args[0] is the executor
   subcommand (`exec`, `dlx`, `x`). The inspector's proposed fix put
   them in the same branch as npx, which is broken — `looksLikePackageName('exec')`
   and `looksLikePackageName('dlx')` both return `true`, so a naive
   scan mis-locates to the subcommand line. Add a separate branch
   that calls `slice(1)` on args before scanning, gated on the
   subcommand being a recognized executor (`npm exec/x`, `yarn dlx`,
   `pnpm dlx/exec/x`). Non-executor `npm foo bar` configs don't
   trigger this path.

Regression tests:
- Bare Bash/Write/Edit assert `high` severity; bare Read asserts
  `medium` to lock the design asymmetry.
- Hand-written .mcp.json with known line numbers asserts that
  bunx / npm exec / yarn dlx line locators all point at the package
  line, not the subcommand line or the server header.
@Conalh Conalh merged commit f266699 into main May 22, 2026
3 checks passed
@Conalh Conalh deleted the bare-verb-severity-and-line-locator branch May 22, 2026 23:29
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