[DOCS] AgentDefinition uses camelCase (disallowedTools) but ClaudeAgentOptions uses snake_case (disallowed_tools) — silent no-op on mismatch

Resolved 💬 2 comments Opened Apr 17, 2026 by brianantonelli Closed May 25, 2026

Description

AgentDefinition (JS-style) uses camelCase field names (disallowedTools, permissionMode, maxTurns), while ClaudeAgentOptions (Python SDK) uses snake_case (disallowed_tools, permission_mode, max_turns).

If you accidentally use the wrong casing — e.g., disallowed_tools=["Bash"] on an AgentDefinition or disallowedTools=["Bash"] on ClaudeAgentOptionsit silently does nothing. No error, no warning, no enforcement. The tool remains available.

This bit us in a production security scanner where we set disallowedTools on AgentDefinition to block Bash, Write, Edit, etc. on 13 agents. The fields were accepted without error but never enforced because one layer used the wrong casing. An LLM agent then executed arbitrary SQL via the Bash tool against our database.

Steps to Reproduce

from claude_agent_sdk import AgentDefinition, ClaudeAgentOptions

# This WORKS — camelCase on AgentDefinition
defn = AgentDefinition(
    description="test",
    prompt="test",
    disallowedTools=["Bash"],  # ✅ correct casing
)

# This SILENTLY DOES NOTHING — snake_case on AgentDefinition
defn = AgentDefinition(
    description="test",
    prompt="test",
    disallowed_tools=["Bash"],  # ❌ wrong casing, no error, Bash still available
)

Expected Behavior

Either:

  1. Raise an error when an unknown field name is passed (strict mode / no extra fields)
  2. Accept both casings and normalize internally
  3. Document the casing contract prominently in the AgentDefinition and ClaudeAgentOptions reference, with a warning callout

Actual Behavior

The wrong-cased field is silently ignored. No error at construction time, no warning in logs. The deny list is never applied.

Environment

  • Claude Agent SDK (Python, via anthropic[bedrock])
  • Claude Code CLI used as the agent runtime
  • AWS Bedrock (Sonnet 4.6 / Opus 4.7)

Additional Context

The subagents.md docs show the correct casing in examples, but the two APIs using different conventions (AgentDefinition = JS camelCase, ClaudeAgentOptions = Python snake_case) is a footgun. A type-checking layer or a model_config = {"extra": "forbid"} on the Pydantic model backing AgentDefinition would catch this at construction time.

Related issues:

  • #19501 (tools + disallowedTools incompatibility)
  • #20242 (confusing tools vs allowed_tools descriptions)
  • #31292 (disallowedTools bypass via Bash sed/awk)

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗