From bc58f39bf060c47648dd1f0a122016f3dcb010e8 Mon Sep 17 00:00:00 2001 From: Ian Jhumel Bautista Date: Tue, 7 Jul 2026 11:51:42 +0800 Subject: [PATCH 1/2] fix: 2026-07-07 audit corrections (ADK ExecuteBashTool + url_context, AG2/OAI guards, timeout callee harmonization, CSDK-121..124, hygiene de-gating) --- autogen/agent_safety.yaml | 29 +++++++-- autogen/network.yaml | 8 +++ claude_sdk/agent_safety.yaml | 106 ++++++++++++++++++++++++++++++++ claude_sdk/network.yaml | 15 +++-- claude_sdk/repo_hygiene.yaml | 1 - google_adk/agent_safety.yaml | 37 ++++++----- google_adk/builtin_tools.yaml | 45 +++++++++----- google_adk/network.yaml | 8 +++ google_adk/repo_hygiene.yaml | 1 - google_adk/tool_definition.yaml | 4 +- mcp/network.yaml | 3 + openai_sdk/approvals.yaml | 79 ++++++++++++++++-------- openai_sdk/idempotency.yaml | 25 ++++---- openai_sdk/mcp_safety.yaml | 8 ++- openai_sdk/network.yaml | 8 +++ openai_sdk/repo_hygiene.yaml | 1 - pydantic_ai/network.yaml | 8 +++ 17 files changed, 294 insertions(+), 92 deletions(-) diff --git a/autogen/agent_safety.yaml b/autogen/agent_safety.yaml index 91262a8..4f838ec 100644 --- a/autogen/agent_safety.yaml +++ b/autogen/agent_safety.yaml @@ -53,8 +53,13 @@ rules: value: NEVER - agent_kwarg_present: - code_execution_config + - not: + agent_kwarg_value: + kwarg: code_execution_config + value: "False" explanation: > - This agent enables code execution (code_execution_config is set) while + This agent enables code execution (code_execution_config is set, and not + to the disabling False) while human_input_mode="NEVER" removes the human-in-the-loop step. The combination makes the agent fully autonomous: every code block the model emits runs with zero review, so a prompt injection or a confused model executes attacker-chosen @@ -102,12 +107,19 @@ rules: - autogen_assistant_agent scope: agent match: - agent_kwarg_present: - - code_execution_config + all: + - agent_kwarg_present: + - code_execution_config + - not: + agent_kwarg_value: + kwarg: code_execution_config + value: "False" explanation: > - This AssistantAgent sets code_execution_config, enabling code execution on the + This AssistantAgent sets code_execution_config to an enabling value, + turning on code execution on the LLM-facing agent. AutoGen's recommended pattern splits responsibilities: the - AssistantAgent generates code with code_execution_config=False, and a separate + AssistantAgent generates code with code_execution_config=False (the safe, + explicit-disable form, which this rule does not flag), and a separate UserProxyAgent (the executor) runs it. Collapsing both roles into one agent removes that review boundary — the same agent that the model fully controls also executes whatever it produces, so a prompt injection has a direct path @@ -131,10 +143,15 @@ rules: all: - agent_kwarg_present: - code_execution_config + - not: + agent_kwarg_value: + kwarg: code_execution_config + value: "False" - agent_kwarg_missing: - max_consecutive_auto_reply explanation: > - This executor enables code execution (code_execution_config is set) but does + This executor enables code execution (code_execution_config is set, and + not to the disabling False) but does not set max_consecutive_auto_reply, so it falls back to AutoGen's class default of 100 (MAX_CONSECUTIVE_AUTO_REPLY). That is a cap, but a very loose one for an agent that auto-executes model-emitted code: up to 100 consecutive diff --git a/autogen/network.yaml b/autogen/network.yaml index a7ce134..15f4445 100644 --- a/autogen/network.yaml +++ b/autogen/network.yaml @@ -33,6 +33,14 @@ rules: - httpx.patch - httpx.head - httpx.request + - requests.Session.get + - requests.Session.post + - urllib.request.urlopen + # Bare `urlopen` covers the from-import form. + - urlopen + # Aliased aiohttp sessions canonicalize to aiohttp.ClientSession.. + - aiohttp.ClientSession.get + - aiohttp.ClientSession.post missing: timeout explanation: > This AutoGen tool makes a network request without a timeout, so it will hang diff --git a/claude_sdk/agent_safety.yaml b/claude_sdk/agent_safety.yaml index 60ee4bc..87acc02 100644 --- a/claude_sdk/agent_safety.yaml +++ b/claude_sdk/agent_safety.yaml @@ -172,6 +172,112 @@ rules: restrict the tool surface, and prefer a safe default permission mode ("default" or "acceptEdits") scoped to a minimal tool set. + - id: CSDK-121 + title: TypeScript AgentDefinition is granted the Bash tool + severity: high + confidence: 0.8 + language: typescript + applies_to: + - claude_agent_definition + scope: agent + match: + agent_grants_builtin_tool: + - Bash + explanation: > + This TypeScript AgentDefinition (a typed const or an inline entry in + options.agents) lists "Bash" in its tools array, giving the subagent + arbitrary shell-command execution. Subagents are dispatched autonomously + by a lead agent in response to model-generated task descriptions, so a + prompt-injected or mis-scoped task can reach the shell with no human in + the loop. This is acute when the surrounding options set + permissionMode: "bypassPermissions", which removes the SDK's interactive + approval gate entirely. + fix: > + Remove "Bash" from this agent definition's tools array unless shell + execution is essential to its job. If it is essential, gate it with a + PreToolUse hook that allowlists the specific commands the subagent may + run, and do not pair it with permissionMode: "bypassPermissions". + + - id: CSDK-122 + title: TypeScript AgentDefinition is granted the WebSearch tool + severity: medium + confidence: 0.8 + language: typescript + applies_to: + - claude_agent_definition + scope: agent + match: + agent_grants_builtin_tool: + - WebSearch + explanation: > + This TypeScript AgentDefinition lists "WebSearch" in its tools array, + giving the subagent access to live internet content. Subagents are + dispatched autonomously by a lead agent; a prompt-injected or mis-scoped + task can direct the subagent to retrieve attacker-controlled pages, whose + content can then inject further instructions into the agentic loop. + WebSearch results are untrusted external data with no SDK-level + filtering — the subagent will process whatever the search returns. + fix: > + Remove "WebSearch" from this agent definition's tools array unless + internet access is essential to its job. If it is essential, gate inbound + queries with a PreToolUse hook that validates the search query before it + executes, and ensure the lead agent that dispatches this subagent + validates task descriptions before passing them down. + + - id: CSDK-123 + title: TypeScript AgentDefinition is granted filesystem-write built-ins + severity: high + confidence: 0.8 + language: typescript + applies_to: + - claude_agent_definition + scope: agent + match: + agent_grants_builtin_tool: + - Write + - Edit + - MultiEdit + - NotebookEdit + explanation: > + This TypeScript AgentDefinition lists a filesystem-write built-in + (Write, Edit, MultiEdit, or NotebookEdit) in its tools array, letting + the subagent modify files on disk. Subagents are dispatched + autonomously; a prompt-injected or mis-scoped task can drive the + subagent to rewrite source, configuration, or even the + .claude/settings.json that governs the agent's own permissions. Write + access is comparable blast radius to shell execution (CSDK-121) and is + not gated by any guardrail mechanism on AgentDefinition itself. + fix: > + Remove the write built-ins from this agent definition's tools array + unless file mutation is essential to its job. If it is essential, scope + the writable area, gate writes with a PreToolUse hook, and never pair + broad write access with permissionMode: "bypassPermissions". + + - id: CSDK-124 + title: TypeScript AgentDefinition is granted the WebFetch tool + severity: high + confidence: 0.75 + language: typescript + applies_to: + - claude_agent_definition + scope: agent + match: + agent_grants_builtin_tool: + - WebFetch + explanation: > + This TypeScript AgentDefinition lists "WebFetch" in its tools array. + WebFetch retrieves a model-chosen URL and feeds its content back into + the agent loop. Unlike WebSearch (CSDK-122), WebFetch takes a direct + URL, so it is both a prompt-injection vector (attacker-controlled page + content re-enters the loop) and a server-side request forgery surface + (the model can point it at internal addresses). Fetched content is + untrusted external data with no SDK-level filtering. + fix: > + Remove "WebFetch" from this agent definition's tools array unless + fetching is essential. If it is essential, gate it with a PreToolUse + hook that allowlists permitted hosts/URLs and blocks internal address + ranges, and validate the task descriptions the lead agent passes down. + - id: CSDK-130 title: TypeScript query() main agent is granted the Bash tool severity: high diff --git a/claude_sdk/network.yaml b/claude_sdk/network.yaml index 6df4b5d..012b513 100644 --- a/claude_sdk/network.yaml +++ b/claude_sdk/network.yaml @@ -36,14 +36,13 @@ rules: - httpx.head - httpx.request - urllib.request.urlopen - # NOTE: these aiohttp.ClientSession.* entries match only DIRECT - # calls of that literal text. The engine's alias resolver - # canonicalizes a reused session (s = aiohttp.ClientSession(); - # s.get(...)) to `aiohttp.get` / `aiohttp.post`, which are NOT in - # this list — so aliased aiohttp sessions are not yet caught. To - # cover them, add `aiohttp.get` / `aiohttp.post` callees here. - # (requests/httpx aliasing already works: their callee lists use the - # `requests.get` / `httpx.post` form the resolver produces.) + # Bare `urlopen` covers the from-import form + # (`from urllib.request import urlopen`). + - urlopen + # The engine's alias resolver canonicalizes a reused session + # (s = aiohttp.ClientSession(); s.get(...)) to + # `aiohttp.ClientSession.get` / `.post`, so these entries match + # both the aliased and the direct form. - aiohttp.ClientSession.get - aiohttp.ClientSession.post missing: timeout diff --git a/claude_sdk/repo_hygiene.yaml b/claude_sdk/repo_hygiene.yaml index 7cb0ebe..604238b 100644 --- a/claude_sdk/repo_hygiene.yaml +++ b/claude_sdk/repo_hygiene.yaml @@ -13,7 +13,6 @@ rules: title: Repo ships Claude Agent SDK code without an agent-guidance doc (AGENTS.md/CLAUDE.md) severity: low confidence: 0.9 - language: python applies_to: - claude_sdk scope: repo diff --git a/google_adk/agent_safety.yaml b/google_adk/agent_safety.yaml index 5bf4911..8854126 100644 --- a/google_adk/agent_safety.yaml +++ b/google_adk/agent_safety.yaml @@ -34,7 +34,7 @@ rules: it as documentation for the parent agent's model. - id: ADK-102 - title: Agent with BashTool has no before_tool_callback + title: Agent with the bash tool has no before_tool_callback severity: high confidence: 0.85 language: python @@ -44,17 +44,19 @@ rules: match: all: - agent_class: [LlmAgent] - - agent_uses_hosted_tool_class: [BashTool] + - agent_uses_hosted_tool_class: [BashTool, ExecuteBashTool] - agent_kwarg_missing: [before_tool_callback] explanation: > - An LlmAgent with `BashTool` in its tools= list can execute + An LlmAgent with the bash tool (`ExecuteBashTool` in current google-adk; + `BashTool` in earlier releases) in its tools= list can execute arbitrary shell commands chosen by the model. ADK's `before_tool_callback` is the only synchronous interception point where you can inspect a tool call before it executes and short-circuit it — the moral analog of an OpenAI agent's - `input_guardrails`. An agent with BashTool and no - `before_tool_callback` has no opportunity to deny a shell command - the model invents. + `input_guardrails`. An agent with the bash tool and no + `before_tool_callback` has no policy of its own over which shell + commands the model invents — only the tool's generic built-in + confirmation prompt stands between the model and execution. fix: > Add a `before_tool_callback=` that inspects the tool name and arguments, allow-lists known-safe commands (or denies known-bad @@ -63,7 +65,7 @@ rules: tool execution. - id: ADK-103 - title: Sub-agent is granted BashTool + title: Sub-agent is granted the bash tool severity: high confidence: 0.9 language: python @@ -73,17 +75,18 @@ rules: match: all: - agent_is_subagent_of_any: true - - agent_uses_hosted_tool_class: [BashTool] + - agent_uses_hosted_tool_class: [BashTool, ExecuteBashTool] explanation: > This LlmAgent appears in another agent's `sub_agents=[...]` tree - AND is granted `BashTool`. A parent agent can delegate to a - child without the child's tool calls being mediated by the - parent's `before_tool_callback`. Granting shell access to a + AND is granted the bash tool (`ExecuteBashTool` in current + google-adk; `BashTool` in earlier releases). A parent agent can + delegate to a child without the child's tool calls being mediated + by the parent's `before_tool_callback`. Granting shell access to a delegated sub-agent makes the parent's policy worthless: the model can route around any safety hook by handing off to the sub-agent and asking it to run the same command. fix: > - Either remove `BashTool` from this sub-agent's tools= list, or + Either remove the bash tool from this sub-agent's tools= list, or restructure so the shell-capable agent is the orchestrator at the top of the tree (so its `before_tool_callback` actually mediates every shell call). @@ -236,11 +239,15 @@ rules: match: all: - agent_class: [LlmAgent] - - agent_uses_hosted_tool_class: [UrlContextTool, LoadWebPage] + - any: + - agent_uses_hosted_tool_class: [UrlContextTool, LoadWebPage] + - agent_grants_builtin_tool: [url_context, load_web_page] - agent_kwarg_missing: [before_tool_callback] explanation: > - This LlmAgent is wired with a URL/page-fetch built-in (UrlContextTool or - LoadWebPage) but has no before_tool_callback. These tools retrieve + This LlmAgent is wired with a URL/page-fetch built-in — the idiomatic + url_context instance or the load_web_page function reference, or a + directly-constructed UrlContextTool — but has no before_tool_callback. + These tools retrieve model-chosen URLs whose content re-enters the agent loop — a prompt injection vector (attacker-controlled page content) and an SSRF surface (the model can point the fetch at internal addresses). Without a callback diff --git a/google_adk/builtin_tools.yaml b/google_adk/builtin_tools.yaml index d9b3e2e..5da3f94 100644 --- a/google_adk/builtin_tools.yaml +++ b/google_adk/builtin_tools.yaml @@ -4,12 +4,12 @@ policy: category: google_adk description: > Rules that flag unsafe configurations on Google ADK built-in tool - classes (BashTool, etc.). Their safety kwargs must be set explicitly — - the defaults are permissive. + classes (the bash tool, etc.). Their safety kwargs must be set + explicitly — the defaults are permissive. rules: - id: ADK-008 - title: Agent grants BashTool with no restrictive command policy + title: Agent grants the bash tool with no restrictive command policy severity: high confidence: 0.75 language: python @@ -17,23 +17,34 @@ rules: - adk_llm_agent scope: agent match: - all: - - agent_uses_hosted_tool_class: [BashTool] - - not: - agent_hosted_tool_kwarg_present: - class: BashTool - kwarg: policy + any: + - all: + - agent_uses_hosted_tool_class: [ExecuteBashTool] + - not: + agent_hosted_tool_kwarg_present: + class: ExecuteBashTool + kwarg: policy + - all: + - agent_uses_hosted_tool_class: [BashTool] + - not: + agent_hosted_tool_kwarg_present: + class: BashTool + kwarg: policy explanation: > - This LlmAgent grants BashTool with no explicit policy=. BashTool runs - shell commands chosen by the model, and its BashToolPolicy defaults to - allowed_command_prefixes=("*",) (every command) and blocked_operators=() - (no shell metacharacters blocked) — i.e. fully injectable. Without a - restrictive policy, model-supplied input reaches the shell with no - command allow-list and no operator filtering. (Earlier google-adk exposed - a block_shell_metacharacters kwarg; current ADK gates this through + This LlmAgent grants the bash tool (ExecuteBashTool in current + google-adk; BashTool in earlier releases) with no explicit policy=. The + tool runs shell commands chosen by the model, and its BashToolPolicy + defaults to allowed_command_prefixes=("*",) (every command) and + blocked_operators=() (no shell metacharacters blocked). The tool does + request a generic user confirmation before each run, but with no policy + that confirmation is the only gate: there is no command allow-list and + no operator filtering between model-supplied input and the shell, so a + convincing or obfuscated command only has to get past a human clicking + through a prompt. (Earlier google-adk exposed a + block_shell_metacharacters kwarg; current ADK gates this through BashToolPolicy instead.) fix: > - Construct BashTool with a restrictive policy=BashToolPolicy(...): set + Construct the tool with a restrictive policy=BashToolPolicy(...): set allowed_command_prefixes to the specific commands the agent needs and blocked_operators to deny shell metacharacters. Pair with a before_tool_callback that validates the command before execution. diff --git a/google_adk/network.yaml b/google_adk/network.yaml index 7d37ce7..354fd69 100644 --- a/google_adk/network.yaml +++ b/google_adk/network.yaml @@ -31,6 +31,14 @@ rules: - httpx.patch - httpx.head - httpx.request + - requests.Session.get + - requests.Session.post + - urllib.request.urlopen + # Bare `urlopen` covers the from-import form. + - urlopen + # Aliased aiohttp sessions canonicalize to aiohttp.ClientSession.. + - aiohttp.ClientSession.get + - aiohttp.ClientSession.post missing: timeout explanation: > An ADK tool that makes a network request without a timeout will diff --git a/google_adk/repo_hygiene.yaml b/google_adk/repo_hygiene.yaml index 21b2235..a38ce0c 100644 --- a/google_adk/repo_hygiene.yaml +++ b/google_adk/repo_hygiene.yaml @@ -12,7 +12,6 @@ rules: title: Google ADK project ships no agent-guidance doc (AGENTS.md/CLAUDE.md) severity: low confidence: 0.9 - language: python applies_to: - google_adk scope: repo diff --git a/google_adk/tool_definition.yaml b/google_adk/tool_definition.yaml index 90c228b..64f860d 100644 --- a/google_adk/tool_definition.yaml +++ b/google_adk/tool_definition.yaml @@ -38,7 +38,9 @@ rules: - adk_function_tool scope: tool match: - has_typed_params: false + all: + - has_params: true + - has_typed_params: false explanation: > Google ADK derives the JSON schema for a FunctionTool's parameters from the wrapped function's type annotations. A function with diff --git a/mcp/network.yaml b/mcp/network.yaml index 63a9501..ad0921a 100644 --- a/mcp/network.yaml +++ b/mcp/network.yaml @@ -37,6 +37,9 @@ rules: - httpx.request - urllib.request.urlopen - urlopen + # Aliased aiohttp sessions canonicalize to aiohttp.ClientSession.. + - aiohttp.ClientSession.get + - aiohttp.ClientSession.post missing: timeout explanation: > An MCP tool handler that makes a network request without a timeout can diff --git a/openai_sdk/approvals.yaml b/openai_sdk/approvals.yaml index 007fdd7..3df7458 100644 --- a/openai_sdk/approvals.yaml +++ b/openai_sdk/approvals.yaml @@ -23,15 +23,21 @@ rules: - has_shell_call: true - has_code_exec_call: true - has_write_call: true - - not: - tool_decorator_kwarg_present: - - needs_approval + - any: + - not: + tool_decorator_kwarg_present: + - needs_approval + - tool_decorator_kwarg_value: + kwarg: needs_approval + value: "False" explanation: > This @function_tool shells out, executes dynamic code, or writes the - filesystem, but sets no needs_approval kwarg. needs_approval is the OpenAI + filesystem, but has no needs_approval gate — the kwarg is absent or + explicitly set to False. needs_approval is the OpenAI Agents SDK's documented human-in-the-loop gate for sensitive tool calls, and its default is False — so an un-gated privileged tool executes - attacker-influenced model output with no human checkpoint. This complements + attacker-influenced model output with no human checkpoint. Passing True + or a per-call approval callable both count as a gate and do not fire. This complements OAI-012 (subprocess) and OAI-013 (eval/exec): those flag the dangerous call; OAI-014 flags the missing approval gate around it. fix: > @@ -54,38 +60,57 @@ rules: any: - all: - agent_uses_hosted_tool_class: [ShellTool] - - not: - agent_hosted_tool_kwarg_value: - class: ShellTool - kwarg: needs_approval - value: "True" + - any: + - not: + agent_hosted_tool_kwarg_present: + class: ShellTool + kwarg: needs_approval + - agent_hosted_tool_kwarg_value: + class: ShellTool + kwarg: needs_approval + value: "False" - all: - agent_uses_hosted_tool_class: [LocalShellTool] - - not: - agent_hosted_tool_kwarg_value: - class: LocalShellTool - kwarg: needs_approval - value: "True" + - any: + - not: + agent_hosted_tool_kwarg_present: + class: LocalShellTool + kwarg: needs_approval + - agent_hosted_tool_kwarg_value: + class: LocalShellTool + kwarg: needs_approval + value: "False" - all: - agent_uses_hosted_tool_class: [CodeInterpreterTool] - - not: - agent_hosted_tool_kwarg_value: - class: CodeInterpreterTool - kwarg: needs_approval - value: "True" + - any: + - not: + agent_hosted_tool_kwarg_present: + class: CodeInterpreterTool + kwarg: needs_approval + - agent_hosted_tool_kwarg_value: + class: CodeInterpreterTool + kwarg: needs_approval + value: "False" - all: - agent_uses_hosted_tool_class: [ApplyPatchTool] - - not: - agent_hosted_tool_kwarg_value: - class: ApplyPatchTool - kwarg: needs_approval - value: "True" + - any: + - not: + agent_hosted_tool_kwarg_present: + class: ApplyPatchTool + kwarg: needs_approval + - agent_hosted_tool_kwarg_value: + class: ApplyPatchTool + kwarg: needs_approval + value: "False" explanation: > This agent wires a privileged hosted tool — ShellTool or LocalShellTool (run shell commands), CodeInterpreterTool (run code), or ApplyPatchTool - (edit files) — without setting needs_approval=True on it. needs_approval + (edit files) — with no needs_approval gate: the kwarg is absent or + explicitly False. needs_approval defaults to False on these tools, so without an explicit opt-in the model - executes commands, code, or file edits with no human checkpoint. + executes commands, code, or file edits with no human checkpoint. Setting + it to True or to a per-call approval callable both count as a gate and + do not fire this rule. needs_approval is the SDK's human-in-the-loop gate for exactly this class of tool. fix: > diff --git a/openai_sdk/idempotency.yaml b/openai_sdk/idempotency.yaml index 255584c..430cf48 100644 --- a/openai_sdk/idempotency.yaml +++ b/openai_sdk/idempotency.yaml @@ -57,14 +57,14 @@ rules: match: all: - name_has_prefix: - - create_ - - send_ - - delete_ - - post_ - - update_ - - refund_ - - charge_ - - issue_ + - create + - send + - delete + - post + - update + - refund + - charge + - issue - not: has_body_text: - idempot @@ -76,16 +76,15 @@ rules: - correlationId explanation: > An OpenAI Agents SDK tool authored in TypeScript whose name implies a - side effect (create_/send_/delete_/refund_/...) has no idempotency token + side effect (create/send/delete/refund/...) has no idempotency token visible in its body. The SDK does not retry tool calls for you by default, but retries still happen — the model re-invokes the tool whenever a result reads as inconclusive, and an orchestrator, your own retry policy, or a lost response (at-least-once delivery) can re-issue the call; without a key threaded through to the backing API the same action fires twice, producing - duplicate tickets, payments, emails, or deletions. Provisional: this rule - loads and - validates today but will not fire until the engine's TypeScript tool - parser ships. + duplicate tickets, payments, emails, or deletions. The prefix set matches + both `create_charge` and `createCharge` naming, so it fires on idiomatic + TypeScript tool names. fix: > Add an `idempotencyKey: string` parameter to the tool's zod schema and forward it to the underlying API (Stripe `Idempotency-Key` header, diff --git a/openai_sdk/mcp_safety.yaml b/openai_sdk/mcp_safety.yaml index 54c9a06..bfaba6b 100644 --- a/openai_sdk/mcp_safety.yaml +++ b/openai_sdk/mcp_safety.yaml @@ -21,6 +21,9 @@ rules: match: all: - agent_kwarg_present: [mcp_servers] + # An empty mcp_servers=[] wires no MCP tools — do not fire on it. + - not: + agent_kwarg_list_empty: [mcp_servers] - agent_kwarg_list_empty: [input_guardrails] explanation: > The agent imports tools from one or more MCP servers (mcp_servers=) @@ -29,8 +32,9 @@ rules: controlled or compromised MCP server can craft tool descriptions that bait the agent into harmful actions — the "tool poisoning" pattern documented in the MCP threat literature. Detection only - fires when mcp_servers is actually configured, so agents without - MCP are unaffected. + fires when mcp_servers is actually configured with at least one + server (an empty list wires nothing), so agents without MCP are + unaffected. fix: > Add at least one @input_guardrail that inspects the user's input AND the resolved tool list before the model is invoked. Pin MCP servers diff --git a/openai_sdk/network.yaml b/openai_sdk/network.yaml index 4f1f097..3799b5c 100644 --- a/openai_sdk/network.yaml +++ b/openai_sdk/network.yaml @@ -24,11 +24,19 @@ rules: - requests.delete - requests.patch - requests.head + - requests.request + - requests.Session.get + - requests.Session.post - httpx.get - httpx.post - httpx.put - httpx.delete - httpx.patch + - httpx.head + - httpx.request + # Aliased aiohttp sessions canonicalize to aiohttp.ClientSession.. + - aiohttp.ClientSession.get + - aiohttp.ClientSession.post missing: timeout explanation: > An OpenAI Agents SDK tool that makes a network request without a diff --git a/openai_sdk/repo_hygiene.yaml b/openai_sdk/repo_hygiene.yaml index 0b367a0..fd222f8 100644 --- a/openai_sdk/repo_hygiene.yaml +++ b/openai_sdk/repo_hygiene.yaml @@ -12,7 +12,6 @@ rules: title: OpenAI Agents project ships no agent-guidance doc (AGENTS.md/CLAUDE.md) severity: low confidence: 0.9 - language: python applies_to: - openai_agents scope: repo diff --git a/pydantic_ai/network.yaml b/pydantic_ai/network.yaml index cbfefb8..117b452 100644 --- a/pydantic_ai/network.yaml +++ b/pydantic_ai/network.yaml @@ -32,6 +32,14 @@ rules: - httpx.patch - httpx.head - httpx.request + - requests.Session.get + - requests.Session.post + - urllib.request.urlopen + # Bare `urlopen` covers the from-import form. + - urlopen + # Aliased aiohttp sessions canonicalize to aiohttp.ClientSession.. + - aiohttp.ClientSession.get + - aiohttp.ClientSession.post missing: timeout explanation: > This Pydantic AI tool makes a network request without a timeout, so it will From 887589c23dec1bcf0498b081db6e3cef38bef2f6 Mon Sep 17 00:00:00 2001 From: Ian Jhumel Bautista Date: Tue, 7 Jul 2026 15:05:50 +0800 Subject: [PATCH 2/2] fix: recalibrate CSKILL-001 to high/0.9 with accurate allowed-tools framing --- claude_skill/skill_safety.yaml | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/claude_skill/skill_safety.yaml b/claude_skill/skill_safety.yaml index e01a18e..34482fd 100644 --- a/claude_skill/skill_safety.yaml +++ b/claude_skill/skill_safety.yaml @@ -11,8 +11,8 @@ policy: rules: - id: CSKILL-001 title: Skill auto-approves unrestricted shell - severity: critical - confidence: 0.95 + severity: high + confidence: 0.9 applies_to: - claude_skill scope: skill @@ -21,14 +21,23 @@ rules: explanation: > This skill's allowed-tools pre-approves unrestricted shell — a bare `Bash` grant or `Bash(*)`. In Claude Code allowed-tools is an auto-approval list, - not a sandbox: while the skill is active Claude runs any shell command it - lists WITHOUT prompting you. Combined with a skill's ability to run bundled - scripts and dynamic-context commands, this is effectively arbitrary local - code execution on activation. + not a sandbox: while the skill is active, any shell command Claude issues + runs without a per-command approval prompt. The grant is bounded — it + applies only while this skill is active, only after the workspace or + plugin is trusted, and a skill cannot change permission modes — but + activation is not only manual: unless disable-model-invocation is set, + Claude can load the skill itself when it judges it relevant. During that + window, a prompt-injected instruction (from a file the skill reads, a + tool result, or fetched content) can run arbitrary commands with no + approval gate, and a bare grant auto-approves far more than the commands + the skill actually needs. fix: > - Replace the wildcard with the specific commands the skill needs, e.g. - `allowed-tools: Bash(git status *) Bash(git diff *)`. Never grant `Bash(*)` - or a bare `Bash` in a skill checked into a shared repository. + Replace the wildcard with the specific command prefixes the skill needs, + e.g. `allowed-tools: Bash(git status *) Bash(git diff *)` — the skill + keeps working, but only its own commands are pre-approved. For + side-effecting workflows, also set `disable-model-invocation: true` so + only the user can activate the skill (see CSKILL-050). Never grant + `Bash(*)` or a bare `Bash` in a skill checked into a shared repository. - id: CSKILL-002 title: Skill runs shell during load (dynamic-context execution)