XtrinelXTRINEL
← Back to research
May 30, 20267 min readXtrinel Research

HYDRACUDA: A Policy Primitive for the AI Tool-Call Attack Surface

Why we built a defensive enforcement layer from the same attack taxonomy that VAAST documents offensively, and what the research community can do with it.

HYDRACUDALLM SecurityMCPTool-Call AbuseDefensive AI SecurityOpen Source

HYDRACUDA is the defensive pillar of the Xtrinel universe, pairing VAAST's offensive findings with a runtime policy engine that can actually stop the same attack classes in production.

When we published the VAAST research log in April, we described four attack classes that together cover most of what actually goes wrong in production LLM systems. One of those classes, tool-call abuse, has a property the others do not: every instance of it is, at its core, a policy violation. The agent called a tool it should not have called, with parameters it should not have used, at a rate it should not have been permitted. The vulnerability is not in the model. It is in the absence of enforcement.

HYDRACUDA is built on that observation.

The enforcement gap

Building VAAST forced us to think carefully about what makes tool-call abuse exploitable in practice. The answer is almost never a clever prompt. It is almost always the same structural condition: there is no enforcement layer between the LLM's tool dispatcher and the actual tool handlers.

The mitigations that exist today sit in the wrong place. Output filters run after the model has already decided to issue a call, the handler may have already fired by the time a filter evaluates the response. RBAC systems are built around human identity, not model-issued requests. System prompt instructions can be overridden by the same injection techniques VAAST tests for. In every case, the defense lives inside or downstream of the thing being attacked.

The only position from which a denial is unconditional is between the dispatcher and the handler, before execution, outside the model's context window. That is where HYDRACUDA sits.

What we actually built

HYDRACUDA is a Python library that intercepts tool calls before they reach your handler. You define a policy file, a plain YAML document committed to your repository, and every call your agent issues is evaluated against it before anything executes.

The three outcomes are explicit and exhaustive:

  • ALLOW: the call passes all policy checks and is forwarded to your handler
  • DENY: the call violates policy and is blocked; a structured error is returned to the model, which can observe the refusal but cannot override it
  • REVIEW: the call is queued for human approval before execution proceeds

The policy file is the source of truth. It is static, version-controlled, and evaluated entirely outside the model's reasoning loop. The model cannot modify it at runtime. A reprompting attack that convinces the model to "ignore the policy" has no effect because the policy is not a prompt instruction, it is code running independently of the context window.

Why the schema is designed the way it is

The HYDRACUDA policy schema is not a generic ACL system with AI branding. Every primitive maps directly to an attack class in the taxonomy we have been documenting through VAAST.

  • deny_patterns on parameters exists because path traversal and parameter injection are the most consistently exploitable tool-call vulnerabilities we find. An agent asked to read /etc/passwd will attempt it if nothing stops it, not because the model is malicious, but because the model is trying to be helpful and has no concept of what paths are dangerous.

  • allow: false on tools exists because privilege escalation through tool availability is a real and underappreciated attack surface. If a tool is in the agent's tool graph, the model will eventually find a way to call it. The correct defense is not to trust that it will not. It is to remove the tool or enforce a hard block at the dispatch layer.

  • allow: review with rate limiting exists because destructive writes without confirmation gates are the category of tool-call abuse most likely to cause irreversible damage. Shell execution, database writes, email sends, these are the calls where the cost of a false negative is not a finding in a scan report, it is a production incident.

  • Default deny for unlisted tools exists because schema confusion, convincing the agent that a new tool exists or that an existing tool has different capabilities, is a documented attack technique. HYDRACUDA fails closed. If a tool has no policy entry, it is denied.

What we tested it against

Before releasing HYDRACUDA we ran it against the Anthropic API directly. We prompted Claude to read /etc/passwd via a read_file tool call. Claude, trying to be helpful, issued the call. HYDRACUDA intercepted it at the dispatch layer before the handler fired:

TEST: Live Anthropic API tool call interception

Model requested:
  read_file({"path": "/etc/passwd"})

HYDRACUDA decision:
  DENY: read_file, parameter "path" matched deny pattern "/etc/"

The model received a structured error. It could not retry with a differently phrased path because the enforcement happened outside the context window. The policy does not care what the model believes it is doing.

The open research questions

We are releasing HYDRACUDA as MIT-licensed open source because the defensive side of the AI security research space is significantly underdeveloped relative to the offensive side. We have good attack taxonomies. We do not yet have good shared infrastructure for enforcing policy against those attacks.

Several directions we think are worth pursuing that we have not built yet:

Stateful policy. The current schema handles per-call parameter rules. Policies that reason across calls, rate limiting by session, cross-tool dependency enforcement, behavioral anomaly detection over time, are not yet expressible. What the right abstraction looks like for stateful enforcement is an open question.

Formal coverage verification. A policy file is a declarative artifact. It should be possible to formally verify coverage properties against a known attack taxonomy without running the tool. We do not yet know what the right formalism is here.

MCP-native enforcement. HYDRACUDA currently operates at the Python library level. An enforcement layer that operates at the MCP protocol layer, intercepting calls before they reach application code in deployments where agent and tools run in separate processes, is architecturally cleaner and more tamper-resistant. The design space here is largely unexplored.

The VAAST bridge. The natural next step is an importer that reads a VAAST scan export and generates a starting hydracuda.yaml from detected vulnerabilities. This would close the loop between offensive findings and defensive configuration in a way that does not currently exist in any tool we are aware of.

Relationship to VAAST

HYDRACUDA is the defensive reference implementation for the attack taxonomy that VAAST documents offensively. They are fully decoupled. HYDRACUDA has no dependency on VAAST or any Xtrinel infrastructure. A researcher who disagrees with every choice we made in VAAST can still use HYDRACUDA, fork it, or build against its policy schema.

We maintain both under Xtrinel because we intend to keep them in sync as the taxonomy grows. When VAAST's MCP Scanner surfaces a new attack class, HYDRACUDA's schema should have a primitive that counters it. Keeping that maintenance commitment as an organizational artifact rather than a personal project makes it easier to sustain.

HYDRACUDA is available now via pip install hydracuda. Source and documentation:

  • GitHub: https://github.com/Xtrinel-Group/HYDRACUDA
  • Docs: https://docs.xtrinel.com/hydracuda
  • Package: https://pypi.org/project/hydracuda

Ready to map your own surface?

Start with the VAAST free tier.

The free tier includes the baseline payload library across the full category catalog. Enough to do a meaningful first pass on a real target.