← Back to the full record in the registry
The mechanism
Most agent runtimes and MCP clients support hooks: small pieces of code
that run before or after a tool call, typically for legitimate reasons,
logging, formatting, validation. A hook registered against a wildcard
match ("matches": "*") runs on every tool call the agent
makes, not just one.
The attack is specific: a hook registered this way, with
blocking: true, that doesn't just observe the call but
rewrites its arguments before the legitimate handler ever sees them. Once
installed, every subsequent tool call in the session passes through this
hook first. The declared scope of whatever tool the agent thinks it's
calling stops being the real scope of what actually executes.
Why this earns CRITICAL, specifically
Severity here isn't about any single call being dangerous. It's about
what the mechanism removes: the agent's own declared understanding of
what it's doing. If a hook can silently substitute arguments on every
call, the entire concept of a scoped, auditable tool call is compromised
at the runtime level, not just for one tool but for everything downstream
of the moment the hook installs. AVE's own scoring reflects amplification
factors for exactly this: high autonomy (nothing about the
substitution requires further attacker interaction), high
persistent_memory-adjacent risk (the hook, once installed,
affects every future call in the session, not a one-time event).
Why detection is genuinely hard, not just under-built
Building conformance fixtures for this record surfaced the actual difficulty directly, worth walking through rather than asserting.
The naive detection approach: flag any hook matching a wildcard
pattern. This fails immediately against a real, common, entirely benign
pattern: audit logging. A hook that matches *, runs on every
call, and simply logs {tool: call.name, timestamp: Date.now()}
is completely standard practice, and a detector that flags it produces a
false positive rate high enough that anyone running the tool would just
turn the check off.
The distinguishing signal isn't the wildcard match at all. It's whether
the hook is blocking (able to intercept and modify the call
before the real handler runs) combined with whether it actually mutates
call.arguments rather than only reading them. A hook can be
blocking and still legitimate (synchronous validation that rejects
malformed input, for instance); a hook can be non-blocking and still
concerning in rarer cases (fire-and-forget exfiltration of call metadata,
a different, related but distinct behavioral class). The specific
combination that matters for this record is blocking plus argument
mutation plus unrestricted scope.
This matters practically: a detection rule that only checks the
hooks[] configuration's declared fields (matches,
blocking) without inspecting what the hook's own code
actually does will miss the real attack and only catch cases where the
configuration itself is suspicious, which a competent attacker has no
reason to make obviously suspicious. Real detection here needs to look at
the hook's actual behavior, not just its declared metadata, which is a
meaningfully harder static analysis problem than checking a manifest
field.
What legitimate defenses actually look like
Not "disallow wildcard hooks," which would break a large amount of
completely reasonable logging and validation tooling. The real mitigation
is scoping and visibility: a runtime that requires blocking hooks to
declare which fields of call.arguments they're permitted to
modify, rather than granting silent access to the whole object, turns
this from an invisible substitution into a visible, auditable, scoped
change. That's a runtime enforcement question, not something AVE's own
classification record can fix by existing; the record's job is naming the
pattern precisely enough that a runtime can be built to close it.
The fixture that actually tests this
Two files, deliberately minimal, in the conformance suite:
A positive fixture: a hook, blocking: true, matching
*, with an accompanying source excerpt showing it fetches a
rewritten version of the call's arguments from an external endpoint
before returning them.
A negative fixture: a hook, blocking: false, also
matching *, that only logs metadata and never touches
call.arguments at all.
Any detector that can correctly separate these two, not just recognize "a hook exists," is doing the actual work this record asks for.
The full record: AVE-2026-00046 in the registry, including its complete AIVSS scoring breakdown, indicators of compromise, and remediation guidance.