This is triage. It is not containment.
The tool does not run in the harness process, does not gate installation, and cannot stop anything. It raises the cost of shipping a hostile plugin and gives you something to read where today you see nothing. That is the whole claim.
A seam at which an install could be stopped does exist — dsh plugin add runs pnpm in the
profile directory, pnpm honours a .pnpmfile.cjs there, and throwing from its async readPackage
hook aborts the install with nothing written to node_modules. Nothing in 0.5 uses it.
ADR.md §11 records the
seam and why shipping a gate on this release’s calibration would have burned the idea. The link
leaves the site on purpose: Pages builds from docs/ alone, so a relative link to a file at the
repository root is a 404 on the published page.
!!js semantics. The loader evaluates these with
new Function('ctx', 'expr', 'with (ctx) { return eval(expr) }') — unrestricted eval, under
with (ctx) scoping. Which identifiers resolve, and to what, depends on the runtime context
object. This tool reports the expression text and its syntactic class. It cannot tell you what
the expression will do.node_modules. The bytes analysed are not guaranteed to be the
bytes that run.dsh.bundle. Reconciliation is by installed state, not by
dependency diff. A package installed today as a plain library that gains a dsh.bundle
declaration in a patch release is mounted automatically by the next dsh plugin update, with
no notice. This is the most likely real-world bypass, and it means a verdict is about one
version and only that version.B8 is the sharpest case: the tool proves a package can read a
credential and can open a socket. It has not shown that the value flows between them, and it
cannot — that needs value tracking this tool does not do. Any telemetry library or
authenticated API client trips B8 legitimately. It fires on 18 % of published plugins, which
is why it is high and not critical.*alias to
it is that same node again in a second position. The reader expands each occurrence to its own
node so the layer is analysed the way the loader composes it, but the file a reviewer reads and
the layer that mounts are then two different documents, and the expansion is bounded — past the
node or nesting ceiling the rest is unread. Any layer using an anchor raises C7, which
degrades the analysis; a clean report over an aliased layer is not a claim that the layer is
clean.+ chain of literals, a template whose spans are literals, or
[…].join(…) over literals — and refused for everything else, including a module-scope const
bound to one of those and used a line later. Refusing is deliberate: resolving a binding is
value tracking, and every attempt to reach a little further has a next case behind it. The
refusal is not silent — it is C2, and it degrades the report.const { provide } = ctx and
const p = ctx.provide leave a bare name that still does everything ctx.provide does, and no
Tier B check matches it, because they all match on the receiver. This tool reports the
detachment rather than following it, so the outcome is a degraded report and not a B1. The
same is true of a context passed into a helper, or ctx.provide.bind(ctx) — neither is
detected, and neither degrades the report either, which is the sharpest remaining hole in
this tier.о U+043E for o, е U+0435 for e — defeats
every one of the eleven rules, including the two hidden-character rules, which look for
invisible characters and not for visible ones that are the wrong letter. Verified against the
rule table, not assumed. Normalisation is not in 0.5; do not read a clean A21/B10 as
evidence that shipped markdown carries no instructions.ctx['pro' + 'vide']('approval', …) defeats seam detection. A computed specifier defeats every
import check. A base64 event name defeats every listener check. Splitting a credential read and a
network call across two packages defeats B8. A Cyrillic о defeats every injection rule.
Those bypasses do not all cost the same. A name that selects a target either folds to a constant
this tool can read, or raises C2 and degrades the report — that covers a computed member on
ctx, a specifier this tool cannot fold, a name assembled at runtime, a base64 decode, and an
API method pulled off its receiver and called through a bare binding. There is no way to hide
which service, module, or event is being reached that leaves the report claiming its negatives
are reliable.
The heuristics that read content rather than select a target are the other half, and they are
silent. B6 matches a credential path written as one string, so a path split across a
concatenation the folder does not reach is missed with no C2. B10 and A21 match English
phrasing, so a homoglyph or a rephrasing is missed with no C2. B8 is a pair, so splitting the
halves across two packages is missed with no C2. Nothing degrades in any of those cases, because
nothing was unreadable: the tool read the bytes and its rule did not match them. So a clean
B6, B10, A21 or B8 is not a claim, whatever analysis.integrity says. negativesReliable
is a statement about whether the analyser could resolve the names it matches on — not a promise
that a heuristic caught what it was looking for.
Three spellings that used to cost nothing at all now cost a finding or a degrade, and the fixture
tests/fixtures/detached-dispatch/ is the record: process.getBuiltinModule('node:fs') reaches a
builtin with no import declaration and is now read as one, a specifier assembled out of string
literals is folded and matched, and const { provide } = ctx followed by
provide.call(ctx, 'approval', …) raises C2 because the receiver every Tier B check matches on
is gone.
Tier A is much harder to hide from, because it is structured declaration rather than code.
The harness must read disabled: true literally in order to disable anything, so there is no
obfuscation that leaves it working. That asymmetry is why Tier A issues verdicts and Tier B
issues capability reports.
If any Tier C check that says something could not be read fires, every Tier B confidence drops to
moderate, analysis.integrity becomes degraded, analysis.negativesReliable becomes false,
and the human report is forbidden from printing “no findings”. A clean-looking report on a
minified bundle would be worse than no report, so the tool refuses to produce one.
The honest form of a clean result is: nothing was found at or above the threshold, in the parts that could be read.