Skip to content

fix(codemode): validate tool arguments against Zod schema before execution#962

Merged
mattzcarey merged 6 commits into
cloudflare:mainfrom
tumberger:security/codemode-validate-tool-args
Feb 24, 2026
Merged

fix(codemode): validate tool arguments against Zod schema before execution#962
mattzcarey merged 6 commits into
cloudflare:mainfrom
tumberger:security/codemode-validate-tool-args

Conversation

@tumberger

@tumberger tumberger commented Feb 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • createCodeTool() extracts .execute functions from tools but discards their Zod schemas, passing them unwrapped to ToolDispatcher
  • ToolDispatcher.call() does JSON.parse(argsJson) → fn(args) with no schema validation, so sandboxed code can invoke tool functions with arbitrary JSON payloads that bypass the constraints defined by tool authors
  • This patch wraps each extracted execute function with its corresponding Zod schema (inputSchema or parameters) so arguments are validated before reaching the tool function — invalid payloads throw a ZodError caught by the existing error handler

Root cause

In tool.ts:101-111 (before this patch):

for (const [name, t] of Object.entries(tools)) {
  const execute = "execute" in t
    ? (t.execute as (args: unknown) => Promise<unknown>)
    : undefined;
  if (execute) {
    fns[sanitizeToolName(name)] = execute; // ← schema discarded
  }
}

The Zod schemas (t.inputSchema / t.parameters) are available but never extracted. When the sandbox calls a tool via ToolDispatcher.call(), the raw JSON.parse'd payload reaches the tool function directly.

Fix

const schema: ZodType | undefined =
  "inputSchema" in t ? (t.inputSchema as ZodType)
  : "parameters" in t ? ((t as Record<string, unknown>).parameters as ZodType)
  : undefined;

fns[sanitizeToolName(name)] = schema
  ? async (args: unknown) => execute(schema.parse(args))
  : execute;

🤖 Generated with Claude Code

…ution

createCodeTool() extracted execute functions from tools but discarded
their Zod schemas. This meant sandboxed code could call tool functions
with arbitrary JSON payloads that bypass the schema constraints defined
by tool authors, since ToolDispatcher.call() passes JSON.parse'd args
directly to fn() without validation.

Now each execute function is wrapped with its corresponding Zod schema
(inputSchema or parameters) so arguments are validated before reaching
the tool function. Invalid payloads throw a ZodError caught by the
existing error handler in ToolDispatcher.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Feb 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cd015da

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/codemode Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Feb 21, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/agents@962
npm i https://pkg.pr.new/cloudflare/agents/@cloudflare/ai-chat@962
npm i https://pkg.pr.new/cloudflare/agents/@cloudflare/codemode@962
npm i https://pkg.pr.new/cloudflare/agents/hono-agents@962

commit: cd015da

@mattzcarey

Copy link
Copy Markdown
Contributor

thanks for this. will look at getting it merged

@mattzcarey
mattzcarey self-requested a review February 23, 2026 10:50
@mattzcarey mattzcarey self-assigned this Feb 23, 2026
mattzcarey and others added 5 commits February 24, 2026 11:03
MCP tools use AI SDK's jsonSchema() wrapper which doesn't have a .parse()
method. Only apply Zod validation to schemas that actually have .parse().
Replace manual Zod duck-typing (.parse check) with the AI SDK's
asSchema() which handles Zod v3/v4, Standard Schema, and JSON Schema
uniformly. No new dependencies — asSchema is exported from `ai`.
@mattzcarey
mattzcarey merged commit ef46d68 into cloudflare:main Feb 24, 2026
4 checks passed
@github-actions github-actions Bot mentioned this pull request Feb 24, 2026
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.

2 participants