diff --git a/POLICY_INDEX.md b/POLICY_INDEX.md index 1ea7828..35304fe 100644 --- a/POLICY_INDEX.md +++ b/POLICY_INDEX.md @@ -43,111 +43,127 @@ Users can contribute their own policies by: | OpenAI Agents SDK | 21 | 9 | 0 | 2 | 32 | [openai_sdk/POLICY_INDEX.md](openai_sdk/POLICY_INDEX.md) | | Google ADK | 14 | 11 | 0 | 1 | 26 | [google_adk/POLICY_INDEX.md](google_adk/POLICY_INDEX.md) | | Model Context Protocol | 14 | 0 | 0 | 0 | 14 | [mcp/POLICY_INDEX.md](mcp/POLICY_INDEX.md) | -| **All** | **66** | **28** | **2** | **6** | **102** | | +| LangChain / LangGraph | 11 | 3 | 0 | 1 | 15 | [langchain/POLICY_INDEX.md](langchain/POLICY_INDEX.md) | +| **All** | **77** | **31** | **2** | **7** | **117** | | ## All rules -| | Id | SDK/ADK | Scope | Applies To | Policy | Severity | Confidence | Risk | Source | -| --- | -------- | ---------- | -------- | ---------------------------------- | ------------------------------------------------------------------------------------- | -------- | ---------- | ---- | ------------------------------------------------------------------------------------------------------------------------- | -| 1 | CSDK-001 | Claude SDK | tool | claude_sdk_tool | Tool has no description | low | 0.95 | 14.3 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | -| 2 | CSDK-002 | Claude SDK | tool | claude_sdk_tool | Tool parameters are not type-annotated | medium | 0.90 | 36.0 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | -| 3 | CSDK-003 | Claude SDK | tool | claude_sdk_tool | Network call has no timeout | high | 0.85 | 59.5 | [claude_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/network.yaml) | -| 4 | CSDK-004 | Claude SDK | tool | claude_sdk_tool | Path parameter used in I/O without validation | high | 0.70 | 49.0 | [claude_sdk/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/path_safety.yaml) | -| 5 | CSDK-005 | Claude SDK | tool | claude_sdk_tool | Tool raises exceptions without a structured error contract | medium | 0.60 | 24.0 | [claude_sdk/error_handling.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/error_handling.yaml) | -| 6 | CSDK-006 | Claude SDK | tool | claude_sdk_tool | Mutating tool has no idempotency key | medium | 0.55 | 22.0 | [claude_sdk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/idempotency.yaml) | -| 7 | CSDK-007 | Claude SDK | tool | claude_sdk_tool | Ambiguous tool name | low | 0.90 | 13.5 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | -| 8 | CSDK-008 | Claude SDK | tool | claude_sdk_tool | Tool exposes **kwargs without explicit input_schema | medium | 0.80 | 32.0 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | -| 9 | CSDK-009 | Claude SDK | tool | claude_sdk_tool | Tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [claude_sdk/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/ssrf.yaml) | -| 10 | CSDK-010 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool shells out to the OS | high | 0.70 | 49.0 | [claude_sdk/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/shell_safety.yaml) | -| 11 | CSDK-011 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool evaluates dynamic code | high | 0.90 | 63.0 | [claude_sdk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/code_execution.yaml) | -| 12 | CSDK-012 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool writes to the filesystem | medium | 0.50 | 20.0 | [claude_sdk/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/path_safety.yaml) | -| 13 | CSDK-013 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [claude_sdk/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/ssrf.yaml) | -| 14 | CSDK-014 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool has no description | low | 0.90 | 13.5 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | -| 15 | CSDK-016 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK mutating tool has no idempotency key | medium | 0.50 | 20.0 | [claude_sdk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/idempotency.yaml) | -| 16 | CSDK-101 | Claude SDK | agent | claude_agent_definition | Claude subagent is granted the Bash tool | high | 0.80 | 56.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | -| 17 | CSDK-102 | Claude SDK | agent | claude_agent_definition | Claude subagent is granted the WebSearch tool | high | 0.80 | 56.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | -| 18 | CSDK-103 | Claude SDK | agent | claude_agent_definition | AgentDefinition sets permissionMode to bypassPermissions | high | 0.90 | 63.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | -| 19 | CSDK-104 | Claude SDK | agent | claude_agent_definition | Claude subagent is granted filesystem-write built-ins | high | 0.80 | 56.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | -| 20 | CSDK-105 | Claude SDK | agent | claude_agent_definition | Claude subagent is granted the WebFetch tool | high | 0.75 | 52.5 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | -| 21 | CSDK-107 | Claude SDK | tool | claude_sdk_tool | Tool body calls eval/exec/compile on dynamic input | high | 0.85 | 59.5 | [claude_sdk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/code_execution.yaml) | -| 22 | CSDK-108 | Claude SDK | tool | claude_sdk_tool | Tool body spawns a subprocess | high | 0.70 | 49.0 | [claude_sdk/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/shell_safety.yaml) | -| 23 | CSDK-110 | Claude SDK | subagent | claude_subagent | Subagent granted the built-in Bash tool | high | 0.90 | 63.0 | [claude_sdk/subagent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/subagent_safety.yaml) | -| 24 | CSDK-111 | Claude SDK | subagent | claude_subagent | Subagent granted filesystem-write or web-fetch built-ins | high | 0.85 | 59.5 | [claude_sdk/subagent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/subagent_safety.yaml) | -| 25 | CSDK-120 | Claude SDK | agent | claude_agent_definition | TypeScript AgentDefinition sets permissionMode to bypassPermissions | high | 0.90 | 63.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | -| 26 | CSDK-130 | Claude SDK | agent | claude_query_main | TypeScript query() main agent is granted the Bash tool | high | 0.80 | 56.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | -| 27 | CSDK-131 | Claude SDK | agent | claude_query_main | TypeScript query() main agent is granted filesystem-write or web-fetch built-ins | high | 0.75 | 52.5 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | -| 28 | CSDK-201 | Claude SDK | repo | claude_sdk | Project default permission mode bypasses approvals | high | 0.90 | 63.0 | [claude_sdk/repo.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/repo.yaml) | -| 29 | CSDK-202 | Claude SDK | repo | claude_sdk | Session permission mode bypasses approvals | high | 0.90 | 63.0 | [claude_sdk/repo.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/repo.yaml) | -| 30 | CSDK-203 | Claude SDK | repo | claude_sdk | Repo ships Claude Agent SDK code without an agent-guidance doc (AGENTS.md/CLAUDE.md) | low | 0.90 | 13.5 | [claude_sdk/repo_hygiene.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/repo_hygiene.yaml) | -| 31 | OAI-001 | OpenAI SDK | tool | openai_tool | Tool function has no docstring | low | 0.90 | 13.5 | [openai_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tool_definition.yaml) | -| 32 | OAI-002 | OpenAI SDK | tool | openai_tool | Tool function has no type-annotated parameters | medium | 0.85 | 34.0 | [openai_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tool_definition.yaml) | -| 33 | OAI-003 | OpenAI SDK | tool | openai_tool | Tool sets strict_mode=False | medium | 0.95 | 38.0 | [openai_sdk/decorator_config.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/decorator_config.yaml) | -| 34 | OAI-004 | OpenAI SDK | tool | openai_tool | Tool has no failure_error_function | medium | 0.70 | 28.0 | [openai_sdk/decorator_config.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/decorator_config.yaml) | -| 35 | OAI-005 | OpenAI SDK | tool | openai_tool | Network call has no timeout | high | 0.85 | 59.5 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | -| 36 | OAI-006 | OpenAI SDK | tool | openai_tool | Tool accepts path without normalization | high | 0.70 | 49.0 | [openai_sdk/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/path_safety.yaml) | -| 37 | OAI-007 | OpenAI SDK | tool | openai_tool | Ambiguous tool name | low | 0.90 | 13.5 | [openai_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tool_definition.yaml) | -| 38 | OAI-008 | OpenAI SDK | tool | openai_tool | Tool raises exceptions without a structured error contract | medium | 0.60 | 24.0 | [openai_sdk/error_handling.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/error_handling.yaml) | -| 39 | OAI-009 | OpenAI SDK | tool | openai_tool | Mutating tool has no idempotency key | medium | 0.55 | 22.0 | [openai_sdk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/idempotency.yaml) | -| 40 | OAI-010 | OpenAI SDK | tool | openai_tool | Tool function prints to stdout for diagnostics | low | 0.65 | 9.8 | [openai_sdk/observability.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/observability.yaml) | -| 41 | OAI-011 | OpenAI SDK | tool | openai_tool | urllib network call has no timeout | high | 0.85 | 59.5 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | -| 42 | OAI-012 | OpenAI SDK | tool | openai_tool | Tool body spawns a subprocess | high | 0.90 | 63.0 | [openai_sdk/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/shell_safety.yaml) | -| 43 | OAI-013 | OpenAI SDK | tool | openai_tool | Tool body calls eval/exec/compile on dynamic input | high | 0.90 | 63.0 | [openai_sdk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/code_execution.yaml) | -| 44 | OAI-014 | OpenAI SDK | tool | openai_tool | Privileged tool has no needs_approval gate | high | 0.70 | 49.0 | [openai_sdk/approvals.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/approvals.yaml) | -| 45 | OAI-015 | OpenAI SDK | tool | openai_tool | Tool sets failure_error_function=None | high | 0.85 | 59.5 | [openai_sdk/decorator_config.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/decorator_config.yaml) | -| 46 | OAI-016 | OpenAI SDK | tool | openai_tool | TypeScript tool fetch call has no AbortSignal timeout | high | 0.60 | 42.0 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | -| 47 | OAI-017 | OpenAI SDK | tool | openai_tool | TypeScript tool body calls eval / new Function on dynamic input | high | 0.90 | 63.0 | [openai_sdk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/code_execution.yaml) | -| 48 | OAI-018 | OpenAI SDK | tool | openai_tool | Tool builds outbound URL from non-literal value | medium | 0.55 | 22.0 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | -| 49 | OAI-019 | OpenAI SDK | tool | openai_tool | TypeScript mutating tool has no idempotency key | medium | 0.50 | 20.0 | [openai_sdk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/idempotency.yaml) | -| 50 | OAI-022 | OpenAI SDK | tool | openai_tool | TypeScript tool has no description | low | 0.85 | 12.8 | [openai_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tool_definition.yaml) | -| 51 | OAI-024 | OpenAI SDK | tool | openai_tool | TypeScript tool builds outbound URL from a non-literal value | medium | 0.60 | 24.0 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | -| 52 | OAI-101 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent has no input_guardrails AND wires shell or filesystem-touching tools | high | 0.85 | 59.5 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | -| 53 | OAI-102 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent uses tool_use_behavior="stop_on_first_tool" | high | 0.95 | 66.5 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | -| 54 | OAI-103 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | tool_choice="required" combined with reset_tool_choice=False | high | 0.95 | 66.5 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | -| 55 | OAI-104 | OpenAI SDK | agent | openai_agent | Raw Agent (not SandboxAgent) wires shell or filesystem-touching tools | medium | 0.75 | 30.0 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | -| 56 | OAI-105 | OpenAI SDK | agent | openai_agent | TypeScript agent wires a content-fetching hosted tool without inputGuardrails | high | 0.80 | 56.0 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | -| 57 | OAI-106 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent wires MCP servers without input_guardrails | high | 0.90 | 63.0 | [openai_sdk/mcp_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/mcp_safety.yaml) | -| 58 | OAI-109 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent uses WebSearchTool without input_guardrails | high | 0.85 | 59.5 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | -| 59 | OAI-110 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent wires a content-fetching tool without output_guardrails | high | 0.60 | 42.0 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | -| 60 | OAI-111 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent wires a privileged hosted tool without needs_approval | high | 0.75 | 52.5 | [openai_sdk/approvals.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/approvals.yaml) | -| 61 | OAI-201 | OpenAI SDK | repo | openai_agents | Project uses default OpenAI tracing | medium | 0.80 | 32.0 | [openai_sdk/tracing.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tracing.yaml) | -| 62 | OAI-202 | OpenAI SDK | repo | openai_agents | OpenAI Agents project ships no agent-guidance doc (AGENTS.md/CLAUDE.md) | low | 0.90 | 13.5 | [openai_sdk/repo_hygiene.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/repo_hygiene.yaml) | -| 63 | ADK-001 | Google ADK | tool | adk_function_tool | FunctionTool-wrapped function has no docstring | low | 0.80 | 12.0 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | -| 64 | ADK-002 | Google ADK | tool | adk_function_tool | FunctionTool-wrapped function has no type-annotated parameters | medium | 0.85 | 34.0 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | -| 65 | ADK-003 | Google ADK | tool | adk_function_tool | Network call has no timeout | high | 0.85 | 59.5 | [google_adk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/network.yaml) | -| 66 | ADK-004 | Google ADK | tool | adk_function_tool | Path parameter used in I/O without normalization | high | 0.70 | 49.0 | [google_adk/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/path_safety.yaml) | -| 67 | ADK-005 | Google ADK | tool | adk_function_tool | Tool raises exceptions without a structured error contract | medium | 0.60 | 24.0 | [google_adk/error_handling.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/error_handling.yaml) | -| 68 | ADK-006 | Google ADK | tool | adk_function_tool | Mutating tool has no idempotency key | medium | 0.55 | 22.0 | [google_adk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/idempotency.yaml) | -| 69 | ADK-007 | Google ADK | tool | adk_function_tool | Ambiguous tool name | low | 0.90 | 13.5 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | -| 70 | ADK-008 | Google ADK | agent | adk_llm_agent | Agent grants BashTool with no restrictive command policy | high | 0.75 | 52.5 | [google_adk/builtin_tools.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/builtin_tools.yaml) | -| 71 | ADK-009 | Google ADK | tool | adk_function_tool | FunctionTool body prints to stdout | low | 0.70 | 10.5 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | -| 72 | ADK-010 | Google ADK | tool | adk_function_tool | Tool body spawns a subprocess | high | 0.90 | 63.0 | [google_adk/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/shell_safety.yaml) | -| 73 | ADK-011 | Google ADK | tool | adk_function_tool | Tool body calls eval/exec/compile on dynamic input | high | 0.90 | 63.0 | [google_adk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/code_execution.yaml) | -| 74 | ADK-012 | Google ADK | tool | adk_function_tool | Tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [google_adk/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/ssrf.yaml) | -| 75 | ADK-013 | Google ADK | tool | adk_function_tool | TypeScript FunctionTool has no description | low | 0.80 | 12.0 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | -| 76 | ADK-015 | Google ADK | tool | adk_function_tool | TypeScript FunctionTool body evaluates dynamic code | high | 0.90 | 63.0 | [google_adk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/code_execution.yaml) | -| 77 | ADK-016 | Google ADK | tool | adk_function_tool | TypeScript FunctionTool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [google_adk/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/ssrf.yaml) | -| 78 | ADK-101 | Google ADK | agent | adk_llm_agent | LlmAgent has no description | medium | 0.85 | 34.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 79 | ADK-102 | Google ADK | agent | adk_llm_agent | Agent with BashTool has no before_tool_callback | high | 0.85 | 59.5 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 80 | ADK-103 | Google ADK | agent | adk_llm_agent | Sub-agent is granted BashTool | high | 0.90 | 63.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 81 | ADK-104 | Google ADK | agent | adk_llm_agent | Agent has no safety_settings | medium | 0.75 | 30.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 82 | ADK-105 | Google ADK | agent | adk_llm_agent | Agent uses web search built-in without before_tool_callback | high | 0.85 | 59.5 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 83 | ADK-106 | Google ADK | agent | adk_llm_agent | Agent has a code_executor but no before_model_callback | high | 0.80 | 56.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 84 | ADK-107 | Google ADK | agent | adk_llm_agent | Agent grants AgentTool but has no before_tool_callback | high | 0.70 | 49.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 85 | ADK-108 | Google ADK | agent | adk_loop_agent | LoopAgent has no max_iterations | medium | 0.70 | 28.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 86 | ADK-109 | Google ADK | agent | adk_llm_agent | TypeScript LlmAgent has no description | medium | 0.85 | 34.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 87 | ADK-110 | Google ADK | agent | adk_llm_agent | Agent fetches web content via UrlContextTool/LoadWebPage without before_tool_callback | medium | 0.70 | 28.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | -| 88 | ADK-201 | Google ADK | repo | google_adk | Google ADK project ships no agent-guidance doc (AGENTS.md/CLAUDE.md) | low | 0.90 | 13.5 | [google_adk/repo_hygiene.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/repo_hygiene.yaml) | -| 89 | MCP-001 | MCP | tool | mcp_tool | Tool has no description | low | 0.90 | 13.5 | [mcp/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/tool_definition.yaml) | -| 90 | MCP-002 | MCP | tool | mcp_tool | Tool has no type-annotated parameters | medium | 0.85 | 34.0 | [mcp/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/tool_definition.yaml) | -| 91 | MCP-003 | MCP | tool | mcp_tool | Ambiguous tool name | low | 0.85 | 12.8 | [mcp/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/tool_definition.yaml) | -| 92 | MCP-004 | MCP | tool | mcp_tool | Network call has no timeout | high | 0.85 | 59.5 | [mcp/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/network.yaml) | -| 93 | MCP-005 | MCP | tool | mcp_tool | Path parameter used in I/O without validation | high | 0.70 | 49.0 | [mcp/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/path_safety.yaml) | -| 94 | MCP-006 | MCP | tool | mcp_tool | Tool raises exceptions without a structured error contract | medium | 0.60 | 24.0 | [mcp/error_handling.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/error_handling.yaml) | -| 95 | MCP-007 | MCP | tool | mcp_tool | Mutating tool has no idempotency key | medium | 0.55 | 22.0 | [mcp/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/idempotency.yaml) | -| 96 | MCP-008 | MCP | tool | mcp_tool | Tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [mcp/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/ssrf.yaml) | -| 97 | MCP-009 | MCP | tool | mcp_tool | Tool body calls eval/exec/compile on dynamic input | high | 0.85 | 59.5 | [mcp/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/code_execution.yaml) | -| 98 | MCP-010 | MCP | tool | mcp_tool | Tool body spawns a subprocess | high | 0.70 | 49.0 | [mcp/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/shell_safety.yaml) | -| 99 | MCP-011 | MCP | tool | mcp_tool | TypeScript MCP tool has no description | low | 0.85 | 12.8 | [mcp/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/tool_definition.yaml) | -| 100 | MCP-012 | MCP | tool | mcp_tool | TypeScript MCP tool spawns a subprocess | high | 0.70 | 49.0 | [mcp/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/shell_safety.yaml) | -| 101 | MCP-013 | MCP | tool | mcp_tool | TypeScript MCP tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [mcp/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/ssrf.yaml) | -| 102 | MCP-014 | MCP | tool | mcp_tool | TypeScript MCP tool evaluates dynamic code | high | 0.90 | 63.0 | [mcp/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/code_execution.yaml) | +| | Id | SDK/ADK | Scope | Applies To | Policy | Severity | Confidence | Risk | Source | +| --- | -------- | ---------- | -------- | ----------------------------------------- | ------------------------------------------------------------------------------------- | -------- | ---------- | ---- | ------------------------------------------------------------------------------------------------------------------------- | +| 1 | CSDK-001 | Claude SDK | tool | claude_sdk_tool | Tool has no description | low | 0.95 | 14.3 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | +| 2 | CSDK-002 | Claude SDK | tool | claude_sdk_tool | Tool parameters are not type-annotated | medium | 0.90 | 36.0 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | +| 3 | CSDK-003 | Claude SDK | tool | claude_sdk_tool | Network call has no timeout | high | 0.85 | 59.5 | [claude_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/network.yaml) | +| 4 | CSDK-004 | Claude SDK | tool | claude_sdk_tool | Path parameter used in I/O without validation | high | 0.70 | 49.0 | [claude_sdk/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/path_safety.yaml) | +| 5 | CSDK-005 | Claude SDK | tool | claude_sdk_tool | Tool raises exceptions without a structured error contract | medium | 0.60 | 24.0 | [claude_sdk/error_handling.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/error_handling.yaml) | +| 6 | CSDK-006 | Claude SDK | tool | claude_sdk_tool | Mutating tool has no idempotency key | medium | 0.55 | 22.0 | [claude_sdk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/idempotency.yaml) | +| 7 | CSDK-007 | Claude SDK | tool | claude_sdk_tool | Ambiguous tool name | low | 0.90 | 13.5 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | +| 8 | CSDK-008 | Claude SDK | tool | claude_sdk_tool | Tool exposes **kwargs without explicit input_schema | medium | 0.80 | 32.0 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | +| 9 | CSDK-009 | Claude SDK | tool | claude_sdk_tool | Tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [claude_sdk/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/ssrf.yaml) | +| 10 | CSDK-010 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool shells out to the OS | high | 0.70 | 49.0 | [claude_sdk/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/shell_safety.yaml) | +| 11 | CSDK-011 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool evaluates dynamic code | high | 0.90 | 63.0 | [claude_sdk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/code_execution.yaml) | +| 12 | CSDK-012 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool writes to the filesystem | medium | 0.50 | 20.0 | [claude_sdk/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/path_safety.yaml) | +| 13 | CSDK-013 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [claude_sdk/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/ssrf.yaml) | +| 14 | CSDK-014 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK tool has no description | low | 0.90 | 13.5 | [claude_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/tool_definition.yaml) | +| 15 | CSDK-016 | Claude SDK | tool | claude_sdk_tool | TypeScript Claude SDK mutating tool has no idempotency key | medium | 0.50 | 20.0 | [claude_sdk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/idempotency.yaml) | +| 16 | CSDK-101 | Claude SDK | agent | claude_agent_definition | Claude subagent is granted the Bash tool | high | 0.80 | 56.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | +| 17 | CSDK-102 | Claude SDK | agent | claude_agent_definition | Claude subagent is granted the WebSearch tool | high | 0.80 | 56.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | +| 18 | CSDK-103 | Claude SDK | agent | claude_agent_definition | AgentDefinition sets permissionMode to bypassPermissions | high | 0.90 | 63.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | +| 19 | CSDK-104 | Claude SDK | agent | claude_agent_definition | Claude subagent is granted filesystem-write built-ins | high | 0.80 | 56.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | +| 20 | CSDK-105 | Claude SDK | agent | claude_agent_definition | Claude subagent is granted the WebFetch tool | high | 0.75 | 52.5 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | +| 21 | CSDK-107 | Claude SDK | tool | claude_sdk_tool | Tool body calls eval/exec/compile on dynamic input | high | 0.85 | 59.5 | [claude_sdk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/code_execution.yaml) | +| 22 | CSDK-108 | Claude SDK | tool | claude_sdk_tool | Tool body spawns a subprocess | high | 0.70 | 49.0 | [claude_sdk/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/shell_safety.yaml) | +| 23 | CSDK-110 | Claude SDK | subagent | claude_subagent | Subagent granted the built-in Bash tool | high | 0.90 | 63.0 | [claude_sdk/subagent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/subagent_safety.yaml) | +| 24 | CSDK-111 | Claude SDK | subagent | claude_subagent | Subagent granted filesystem-write or web-fetch built-ins | high | 0.85 | 59.5 | [claude_sdk/subagent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/subagent_safety.yaml) | +| 25 | CSDK-120 | Claude SDK | agent | claude_agent_definition | TypeScript AgentDefinition sets permissionMode to bypassPermissions | high | 0.90 | 63.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | +| 26 | CSDK-130 | Claude SDK | agent | claude_query_main | TypeScript query() main agent is granted the Bash tool | high | 0.80 | 56.0 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | +| 27 | CSDK-131 | Claude SDK | agent | claude_query_main | TypeScript query() main agent is granted filesystem-write or web-fetch built-ins | high | 0.75 | 52.5 | [claude_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/agent_safety.yaml) | +| 28 | CSDK-201 | Claude SDK | repo | claude_sdk | Project default permission mode bypasses approvals | high | 0.90 | 63.0 | [claude_sdk/repo.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/repo.yaml) | +| 29 | CSDK-202 | Claude SDK | repo | claude_sdk | Session permission mode bypasses approvals | high | 0.90 | 63.0 | [claude_sdk/repo.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/repo.yaml) | +| 30 | CSDK-203 | Claude SDK | repo | claude_sdk | Repo ships Claude Agent SDK code without an agent-guidance doc (AGENTS.md/CLAUDE.md) | low | 0.90 | 13.5 | [claude_sdk/repo_hygiene.yaml](https://github.com/trustabl/trustabl-rules/blob/main/claude_sdk/repo_hygiene.yaml) | +| 31 | OAI-001 | OpenAI SDK | tool | openai_tool | Tool function has no docstring | low | 0.90 | 13.5 | [openai_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tool_definition.yaml) | +| 32 | OAI-002 | OpenAI SDK | tool | openai_tool | Tool function has no type-annotated parameters | medium | 0.85 | 34.0 | [openai_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tool_definition.yaml) | +| 33 | OAI-003 | OpenAI SDK | tool | openai_tool | Tool sets strict_mode=False | medium | 0.95 | 38.0 | [openai_sdk/decorator_config.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/decorator_config.yaml) | +| 34 | OAI-004 | OpenAI SDK | tool | openai_tool | Tool has no failure_error_function | medium | 0.70 | 28.0 | [openai_sdk/decorator_config.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/decorator_config.yaml) | +| 35 | OAI-005 | OpenAI SDK | tool | openai_tool | Network call has no timeout | high | 0.85 | 59.5 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | +| 36 | OAI-006 | OpenAI SDK | tool | openai_tool | Tool accepts path without normalization | high | 0.70 | 49.0 | [openai_sdk/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/path_safety.yaml) | +| 37 | OAI-007 | OpenAI SDK | tool | openai_tool | Ambiguous tool name | low | 0.90 | 13.5 | [openai_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tool_definition.yaml) | +| 38 | OAI-008 | OpenAI SDK | tool | openai_tool | Tool raises exceptions without a structured error contract | medium | 0.60 | 24.0 | [openai_sdk/error_handling.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/error_handling.yaml) | +| 39 | OAI-009 | OpenAI SDK | tool | openai_tool | Mutating tool has no idempotency key | medium | 0.55 | 22.0 | [openai_sdk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/idempotency.yaml) | +| 40 | OAI-010 | OpenAI SDK | tool | openai_tool | Tool function prints to stdout for diagnostics | low | 0.65 | 9.8 | [openai_sdk/observability.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/observability.yaml) | +| 41 | OAI-011 | OpenAI SDK | tool | openai_tool | urllib network call has no timeout | high | 0.85 | 59.5 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | +| 42 | OAI-012 | OpenAI SDK | tool | openai_tool | Tool body spawns a subprocess | high | 0.90 | 63.0 | [openai_sdk/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/shell_safety.yaml) | +| 43 | OAI-013 | OpenAI SDK | tool | openai_tool | Tool body calls eval/exec/compile on dynamic input | high | 0.90 | 63.0 | [openai_sdk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/code_execution.yaml) | +| 44 | OAI-014 | OpenAI SDK | tool | openai_tool | Privileged tool has no needs_approval gate | high | 0.70 | 49.0 | [openai_sdk/approvals.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/approvals.yaml) | +| 45 | OAI-015 | OpenAI SDK | tool | openai_tool | Tool sets failure_error_function=None | high | 0.85 | 59.5 | [openai_sdk/decorator_config.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/decorator_config.yaml) | +| 46 | OAI-016 | OpenAI SDK | tool | openai_tool | TypeScript tool fetch call has no AbortSignal timeout | high | 0.60 | 42.0 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | +| 47 | OAI-017 | OpenAI SDK | tool | openai_tool | TypeScript tool body calls eval / new Function on dynamic input | high | 0.90 | 63.0 | [openai_sdk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/code_execution.yaml) | +| 48 | OAI-018 | OpenAI SDK | tool | openai_tool | Tool builds outbound URL from non-literal value | medium | 0.55 | 22.0 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | +| 49 | OAI-019 | OpenAI SDK | tool | openai_tool | TypeScript mutating tool has no idempotency key | medium | 0.50 | 20.0 | [openai_sdk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/idempotency.yaml) | +| 50 | OAI-022 | OpenAI SDK | tool | openai_tool | TypeScript tool has no description | low | 0.85 | 12.8 | [openai_sdk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tool_definition.yaml) | +| 51 | OAI-024 | OpenAI SDK | tool | openai_tool | TypeScript tool builds outbound URL from a non-literal value | medium | 0.60 | 24.0 | [openai_sdk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/network.yaml) | +| 52 | OAI-101 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent has no input_guardrails AND wires shell or filesystem-touching tools | high | 0.85 | 59.5 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | +| 53 | OAI-102 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent uses tool_use_behavior="stop_on_first_tool" | high | 0.95 | 66.5 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | +| 54 | OAI-103 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | tool_choice="required" combined with reset_tool_choice=False | high | 0.95 | 66.5 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | +| 55 | OAI-104 | OpenAI SDK | agent | openai_agent | Raw Agent (not SandboxAgent) wires shell or filesystem-touching tools | medium | 0.75 | 30.0 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | +| 56 | OAI-105 | OpenAI SDK | agent | openai_agent | TypeScript agent wires a content-fetching hosted tool without inputGuardrails | high | 0.80 | 56.0 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | +| 57 | OAI-106 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent wires MCP servers without input_guardrails | high | 0.90 | 63.0 | [openai_sdk/mcp_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/mcp_safety.yaml) | +| 58 | OAI-109 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent uses WebSearchTool without input_guardrails | high | 0.85 | 59.5 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | +| 59 | OAI-110 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent wires a content-fetching tool without output_guardrails | high | 0.60 | 42.0 | [openai_sdk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/agent_safety.yaml) | +| 60 | OAI-111 | OpenAI SDK | agent | openai_agent, openai_sandbox_agent | Agent wires a privileged hosted tool without needs_approval | high | 0.75 | 52.5 | [openai_sdk/approvals.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/approvals.yaml) | +| 61 | OAI-201 | OpenAI SDK | repo | openai_agents | Project uses default OpenAI tracing | medium | 0.80 | 32.0 | [openai_sdk/tracing.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/tracing.yaml) | +| 62 | OAI-202 | OpenAI SDK | repo | openai_agents | OpenAI Agents project ships no agent-guidance doc (AGENTS.md/CLAUDE.md) | low | 0.90 | 13.5 | [openai_sdk/repo_hygiene.yaml](https://github.com/trustabl/trustabl-rules/blob/main/openai_sdk/repo_hygiene.yaml) | +| 63 | ADK-001 | Google ADK | tool | adk_function_tool | FunctionTool-wrapped function has no docstring | low | 0.80 | 12.0 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | +| 64 | ADK-002 | Google ADK | tool | adk_function_tool | FunctionTool-wrapped function has no type-annotated parameters | medium | 0.85 | 34.0 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | +| 65 | ADK-003 | Google ADK | tool | adk_function_tool | Network call has no timeout | high | 0.85 | 59.5 | [google_adk/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/network.yaml) | +| 66 | ADK-004 | Google ADK | tool | adk_function_tool | Path parameter used in I/O without normalization | high | 0.70 | 49.0 | [google_adk/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/path_safety.yaml) | +| 67 | ADK-005 | Google ADK | tool | adk_function_tool | Tool raises exceptions without a structured error contract | medium | 0.60 | 24.0 | [google_adk/error_handling.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/error_handling.yaml) | +| 68 | ADK-006 | Google ADK | tool | adk_function_tool | Mutating tool has no idempotency key | medium | 0.55 | 22.0 | [google_adk/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/idempotency.yaml) | +| 69 | ADK-007 | Google ADK | tool | adk_function_tool | Ambiguous tool name | low | 0.90 | 13.5 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | +| 70 | ADK-008 | Google ADK | agent | adk_llm_agent | Agent grants BashTool with no restrictive command policy | high | 0.75 | 52.5 | [google_adk/builtin_tools.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/builtin_tools.yaml) | +| 71 | ADK-009 | Google ADK | tool | adk_function_tool | FunctionTool body prints to stdout | low | 0.70 | 10.5 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | +| 72 | ADK-010 | Google ADK | tool | adk_function_tool | Tool body spawns a subprocess | high | 0.90 | 63.0 | [google_adk/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/shell_safety.yaml) | +| 73 | ADK-011 | Google ADK | tool | adk_function_tool | Tool body calls eval/exec/compile on dynamic input | high | 0.90 | 63.0 | [google_adk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/code_execution.yaml) | +| 74 | ADK-012 | Google ADK | tool | adk_function_tool | Tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [google_adk/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/ssrf.yaml) | +| 75 | ADK-013 | Google ADK | tool | adk_function_tool | TypeScript FunctionTool has no description | low | 0.80 | 12.0 | [google_adk/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/tool_definition.yaml) | +| 76 | ADK-015 | Google ADK | tool | adk_function_tool | TypeScript FunctionTool body evaluates dynamic code | high | 0.90 | 63.0 | [google_adk/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/code_execution.yaml) | +| 77 | ADK-016 | Google ADK | tool | adk_function_tool | TypeScript FunctionTool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [google_adk/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/ssrf.yaml) | +| 78 | ADK-101 | Google ADK | agent | adk_llm_agent | LlmAgent has no description | medium | 0.85 | 34.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 79 | ADK-102 | Google ADK | agent | adk_llm_agent | Agent with BashTool has no before_tool_callback | high | 0.85 | 59.5 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 80 | ADK-103 | Google ADK | agent | adk_llm_agent | Sub-agent is granted BashTool | high | 0.90 | 63.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 81 | ADK-104 | Google ADK | agent | adk_llm_agent | Agent has no safety_settings | medium | 0.75 | 30.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 82 | ADK-105 | Google ADK | agent | adk_llm_agent | Agent uses web search built-in without before_tool_callback | high | 0.85 | 59.5 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 83 | ADK-106 | Google ADK | agent | adk_llm_agent | Agent has a code_executor but no before_model_callback | high | 0.80 | 56.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 84 | ADK-107 | Google ADK | agent | adk_llm_agent | Agent grants AgentTool but has no before_tool_callback | high | 0.70 | 49.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 85 | ADK-108 | Google ADK | agent | adk_loop_agent | LoopAgent has no max_iterations | medium | 0.70 | 28.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 86 | ADK-109 | Google ADK | agent | adk_llm_agent | TypeScript LlmAgent has no description | medium | 0.85 | 34.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 87 | ADK-110 | Google ADK | agent | adk_llm_agent | Agent fetches web content via UrlContextTool/LoadWebPage without before_tool_callback | medium | 0.70 | 28.0 | [google_adk/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/agent_safety.yaml) | +| 88 | ADK-201 | Google ADK | repo | google_adk | Google ADK project ships no agent-guidance doc (AGENTS.md/CLAUDE.md) | low | 0.90 | 13.5 | [google_adk/repo_hygiene.yaml](https://github.com/trustabl/trustabl-rules/blob/main/google_adk/repo_hygiene.yaml) | +| 89 | MCP-001 | MCP | tool | mcp_tool | Tool has no description | low | 0.90 | 13.5 | [mcp/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/tool_definition.yaml) | +| 90 | MCP-002 | MCP | tool | mcp_tool | Tool has no type-annotated parameters | medium | 0.85 | 34.0 | [mcp/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/tool_definition.yaml) | +| 91 | MCP-003 | MCP | tool | mcp_tool | Ambiguous tool name | low | 0.85 | 12.8 | [mcp/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/tool_definition.yaml) | +| 92 | MCP-004 | MCP | tool | mcp_tool | Network call has no timeout | high | 0.85 | 59.5 | [mcp/network.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/network.yaml) | +| 93 | MCP-005 | MCP | tool | mcp_tool | Path parameter used in I/O without validation | high | 0.70 | 49.0 | [mcp/path_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/path_safety.yaml) | +| 94 | MCP-006 | MCP | tool | mcp_tool | Tool raises exceptions without a structured error contract | medium | 0.60 | 24.0 | [mcp/error_handling.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/error_handling.yaml) | +| 95 | MCP-007 | MCP | tool | mcp_tool | Mutating tool has no idempotency key | medium | 0.55 | 22.0 | [mcp/idempotency.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/idempotency.yaml) | +| 96 | MCP-008 | MCP | tool | mcp_tool | Tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [mcp/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/ssrf.yaml) | +| 97 | MCP-009 | MCP | tool | mcp_tool | Tool body calls eval/exec/compile on dynamic input | high | 0.85 | 59.5 | [mcp/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/code_execution.yaml) | +| 98 | MCP-010 | MCP | tool | mcp_tool | Tool body spawns a subprocess | high | 0.70 | 49.0 | [mcp/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/shell_safety.yaml) | +| 99 | MCP-011 | MCP | tool | mcp_tool | TypeScript MCP tool has no description | low | 0.85 | 12.8 | [mcp/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/tool_definition.yaml) | +| 100 | MCP-012 | MCP | tool | mcp_tool | TypeScript MCP tool spawns a subprocess | high | 0.70 | 49.0 | [mcp/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/shell_safety.yaml) | +| 101 | MCP-013 | MCP | tool | mcp_tool | TypeScript MCP tool fetches a caller-controlled URL (SSRF) | high | 0.60 | 42.0 | [mcp/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/ssrf.yaml) | +| 102 | MCP-014 | MCP | tool | mcp_tool | TypeScript MCP tool evaluates dynamic code | high | 0.90 | 63.0 | [mcp/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/mcp/code_execution.yaml) | +| 103 | LC-001 | LangChain | tool | langchain_tool | LangChain tool has no description | low | 0.80 | 12.0 | [langchain/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_definition.yaml) | +| 104 | LC-002 | LangChain | tool | langchain_tool | LangChain tool parameters are not type-annotated | medium | 0.85 | 34.0 | [langchain/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_definition.yaml) | +| 105 | LC-003 | LangChain | tool | langchain_tool | LangChain tool body spawns a subprocess | high | 0.85 | 59.5 | [langchain/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/shell_safety.yaml) | +| 106 | LC-004 | LangChain | tool | langchain_tool | LangChain tool body evaluates dynamic code | high | 0.85 | 59.5 | [langchain/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/code_execution.yaml) | +| 107 | LC-005 | LangChain | tool | langchain_tool | LangChain tool fetches a caller-controlled URL (SSRF) | high | 0.80 | 56.0 | [langchain/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/ssrf.yaml) | +| 108 | LC-006 | LangChain | tool | langchain_tool | LangChain tool returns its output directly, bypassing the model | medium | 0.80 | 32.0 | [langchain/tool_behavior.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_behavior.yaml) | +| 109 | LC-010 | LangChain | tool | langchain_tool | TypeScript LangChain tool has no description | low | 0.80 | 12.0 | [langchain/tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_definition.yaml) | +| 110 | LC-011 | LangChain | tool | langchain_tool | TypeScript LangChain tool body spawns a subprocess | high | 0.85 | 59.5 | [langchain/shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/shell_safety.yaml) | +| 111 | LC-012 | LangChain | tool | langchain_tool | TypeScript LangChain tool evaluates dynamic code | high | 0.85 | 59.5 | [langchain/code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/code_execution.yaml) | +| 112 | LC-013 | LangChain | tool | langchain_tool | TypeScript LangChain tool fetches a caller-controlled URL (SSRF) | high | 0.80 | 56.0 | [langchain/ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/ssrf.yaml) | +| 113 | LC-014 | LangChain | tool | langchain_tool | TypeScript LangChain tool returns its output directly, bypassing the model | medium | 0.80 | 32.0 | [langchain/tool_behavior.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_behavior.yaml) | +| 114 | LC-101 | LangChain | agent | langchain_agent, langchain_agent_executor | LangChain agent wires a code-execution or shell built-in tool | high | 0.85 | 59.5 | [langchain/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/agent_safety.yaml) | +| 115 | LC-102 | LangChain | agent | langchain_agent_executor | LangChain AgentExecutor has no max_iterations limit | medium | 0.80 | 32.0 | [langchain/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/agent_safety.yaml) | +| 116 | LC-111 | LangChain | agent | langchain_agent_executor | TypeScript LangChain AgentExecutor has no maxIterations limit | medium | 0.80 | 32.0 | [langchain/agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/agent_safety.yaml) | +| 117 | LC-201 | LangChain | repo | langchain | LangChain project ships no agent-guidance doc (AGENTS.md/CLAUDE.md) | low | 0.90 | 13.5 | [langchain/repo_hygiene.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/repo_hygiene.yaml) | diff --git a/docs/Policy/langchain/agent_safety.md b/docs/Policy/langchain/agent_safety.md new file mode 100644 index 0000000..3b6626b --- /dev/null +++ b/docs/Policy/langchain/agent_safety.md @@ -0,0 +1,116 @@ +--- +policy_id: langchain_agent_safety +category: langchain +topic: agent_safety +rules: + - id: LC-101 + severity: high + confidence: 0.85 + scope: agent + fix_type: code + - id: LC-102 + severity: medium + confidence: 0.8 + scope: agent + fix_type: config + - id: LC-111 + severity: medium + confidence: 0.8 + scope: agent + fix_type: config +references: [LLM06, LLM10] +--- + +# Policy Rationale: LangChain Agent Safety + +**Policy ID:** `langchain_agent_safety` +**File:** `langchain/agent_safety.yaml` +**Rules:** LC-101, LC-102, LC-111 +**Severities:** high, medium +**Fix types:** code, config +**References:** LLM06 (Excessive Agency), LLM10 (Unbounded Consumption) + +--- + +## What this policy covers + +Agent-scope rules for the constructor-shaped LangChain / LangGraph agents Trustabl +discovers: `create_react_agent` and `create_agent` (normalized class `ReactAgent` / +`CreateAgent`) and the legacy `AgentExecutor`. The rules cover the two highest-signal +agent-level risks: wiring a code-execution/shell built-in tool (LC-101) and an +unbounded tool-calling loop (LC-102 / LC-111). + +The raw `StateGraph` graph agent is a documented discovery gap — its tools and model +are assembled across many call sites, so it is not yet modeled as a single agent. + +--- + +## Rule-by-rule defense + +### LC-101 — Agent wires a code-execution or shell built-in tool (Severity: high, Confidence: 0.85, Fix type: code) + +**What we detect:** a LangChain agent (`ReactAgent` / `CreateAgent` / `AgentExecutor`) +whose resolved tool set includes `PythonREPLTool`, `PythonAstREPLTool`, or +`ShellTool` (predicate `agent_uses_hosted_tool_class`). Discovery recognizes these +built-ins when they appear in the agent's tool list — including the common +positional form, `create_react_agent(model, [PythonREPLTool()])` — and records them +as hosted-tool edges. + +**Why it is flaggable:** these built-ins execute code or shell commands chosen by +the model. Once one is on the tool surface, a prompt injection or a confused model +has a direct path to arbitrary execution in the agent process. PythonREPLTool and +ShellTool have been the concrete vector in multiple published LangChain RCE +advisories — this is excessive agency (LLM06) in its most literal form: the agent is +granted the ability to run anything. + +**Real-world consequence:** an agent built to "answer questions about a CSV" is +given a `PythonREPLTool`; a crafted question makes it run `__import__('os').system(...)` +and read the deployment's secrets. + +**Severity high:** the capability is the defect; the fix is to remove the built-in or +sandbox-and-gate it. **Confidence 0.85:** a few agents legitimately need a REPL and +have sandboxed it out of band, which the class-name match cannot see. + +### LC-102 — AgentExecutor has no max_iterations limit (Severity: medium, Confidence: 0.8, Fix type: config) + +**What we detect:** an `AgentExecutor` with no effective `max_iterations` kwarg +(predicate `agent_kwarg_missing`). + +**Why it is flaggable:** with no iteration ceiling, a model that never emits a final +answer — it loops calling tools, or oscillates between two — runs until it exhausts +the API budget or wall-clock (LLM10, Unbounded Consumption). When the looped tools +have side effects, the runaway loop is also a correctness and safety problem, not +just a cost one. + +**Severity medium:** a cost/availability incident rather than a direct compromise. +**Confidence 0.8:** an executor wrapped by an external timeout or a custom loop +guard is over-flagged. + +### LC-111 — TypeScript AgentExecutor has no maxIterations limit (Severity: medium, Confidence: 0.8, Fix type: config) + +**What we detect:** a TS `AgentExecutor` with no effective `maxIterations` kwarg. + +**Why it is flaggable / consequence:** identical to LC-102 in LangChain.js. + +**Severity medium / Confidence 0.8:** same profile. + +--- + +## What this policy does not cover + +The raw `StateGraph` agent (discovery gap), the `Requests*` SSRF built-ins (recorded +as hosted edges but not yet a dedicated agent rule), v1 `create_agent` middleware +quality, and whether a code-execution tool is *actually* sandboxed out of band. The +iteration rules check `AgentExecutor` only — `create_react_agent` / `create_agent` +enforce their own recursion limit differently and are out of scope here. + +--- + +## Recommendations beyond the fix + +Remove REPL/shell built-ins from production agents; if code execution is required, +run it in an isolated sandbox and gate it behind a human-in-the-loop approval (a +LangGraph `interrupt_before` breakpoint or a tool-approval middleware). Set +`max_iterations` / `maxIterations` (and a `max_execution_time`) sized to the task, +and set `handle_parsing_errors` so a malformed model step surfaces rather than +retrying forever. diff --git a/docs/Policy/langchain/code_execution.md b/docs/Policy/langchain/code_execution.md new file mode 100644 index 0000000..83f397f --- /dev/null +++ b/docs/Policy/langchain/code_execution.md @@ -0,0 +1,101 @@ +--- +policy_id: langchain_code_execution +category: langchain +topic: code_execution +rules: + - id: LC-004 + severity: high + confidence: 0.85 + scope: tool + fix_type: code + - id: LC-012 + severity: high + confidence: 0.85 + scope: tool + fix_type: code +references: [LLM05, LLM06] +--- + +# Policy Rationale: LangChain Dynamic Code Execution + +**Policy ID:** `langchain_code_execution` +**File:** `langchain/code_execution.yaml` +**Rules:** LC-004, LC-012 +**Severities:** high +**Fix types:** code +**References:** LLM05 (Improper Output Handling), LLM06 (Excessive Agency) + +> **Read [openai_sdk/code_execution.md](../openai_sdk/code_execution.md) for the +> full threat model.** This document covers the LangChain-specific differences only. + +--- + +## What this policy covers + +LangChain tools whose body evaluates code at runtime. Python (LC-004) fires on a +bare `eval` / `exec` / `compile` callee (predicate `has_code_exec_call`, an AST +walk). TypeScript (LC-012) reads the `code_exec` discovery fact, set when a handler +calls `eval` or constructs `new Function(...)`. + +--- + +## Why dynamic evaluation is a distinct concern in LangChain agents + +The mechanism is identical to the OpenAI case — a model-influenced string reaching +an interpreter is arbitrary code execution; see +[openai_sdk/code_execution.md](../openai_sdk/code_execution.md). The +LangChain-specific note is that this ecosystem *ships* code execution as a feature: +`PythonREPLTool` / `PythonAstREPLTool` (flagged at agent scope by LC-101) and the +pandas/CSV/SQL "dataframe" agents are built on a REPL. Hand-rolling `eval()` inside +a `@tool` reproduces that capability with none of the (already thin) sandboxing the +REPL tools attempt, and hides it inside an ordinary tool body. The result reaches +the model and the user unsanitized (LLM05), and the model can drive it (LLM06). + +--- + +## Rule-by-rule defense + +### LC-004 — Python tool body evaluates dynamic code (Severity: high, Confidence: 0.85, Fix type: code) + +**What we detect:** a Python LangChain tool whose body calls `eval`, `exec`, or +`compile` as a bare builtin (so `re.compile` and other attribute calls are not +flagged). + +**Why it is flaggable / consequence:** a tool that evaluates its string input can +be steered by prompt injection to run attacker-chosen Python in the agent process — +read secrets, pivot to the network, or rewrite state. + +**Severity high:** the fix is to remove the evaluation or sandbox it; partial input +filtering does not contain `eval`. **Confidence 0.85:** the bare-callee match +avoids the obvious false positives, but a tool that only ever evaluates a trusted +constant is over-flagged. + +### LC-012 — TypeScript tool evaluates dynamic code (Severity: high, Confidence: 0.85, Fix type: code) + +**What we detect:** a TS LangChain tool whose handler calls `eval()` or +`new Function(...)` (the `code_exec` fact). + +**Why it is flaggable / consequence:** identical in the Node runtime — both +evaluate a string as code, so a model-influenced argument is RCE. + +**Severity high / Confidence 0.85:** same profile as LC-004. + +--- + +## What this policy does not cover + +Indirect evaluation (`importlib`, `pickle.loads`, `vm.runInContext`, a templating +engine with code execution), evaluation behind a cross-module helper, and the +`PythonREPLTool` built-in itself (agent scope, LC-101). Whether a given evaluated +string is attacker-reachable is not proven — the presence of the primitive is the +signal. + +--- + +## Recommendations beyond the fix + +Parse structured input with a real parser (`ast.literal_eval` / `JSON.parse` / a +typed schema) instead of evaluating it. If code execution is genuinely the product, +run it in a locked-down sandbox (no filesystem, no network, no credentials, hard +timeout) and gate it behind a human approval rather than letting the model invoke +it unattended. diff --git a/docs/Policy/langchain/repo_hygiene.md b/docs/Policy/langchain/repo_hygiene.md new file mode 100644 index 0000000..7dfb374 --- /dev/null +++ b/docs/Policy/langchain/repo_hygiene.md @@ -0,0 +1,94 @@ +--- +policy_id: langchain_repo_hygiene +category: langchain +topic: repo_hygiene +rules: + - id: LC-201 + severity: low + confidence: 0.9 + scope: repo + fix_type: config +references: [LLM06] +--- + +# Policy Rationale: LangChain Repo Hygiene + +**Policy ID:** `langchain_repo_hygiene` +**File:** `langchain/repo_hygiene.yaml` +**Rules:** LC-201 +**Severities:** low +**Fix types:** config +**References:** LLM06 (Excessive Agency) + +> This rule is one of the cross-SDK "missing agent-guidance doc" family. See +> [openai_sdk/repo_hygiene.md](../openai_sdk/repo_hygiene.md) and +> [google_adk/repo_hygiene.md](../google_adk/repo_hygiene.md) for the shared +> rationale; this document covers the LangChain-specific framing. + +--- + +## What this policy covers + +A repo that uses LangChain / LangGraph in code (`SDKLangChain` observed in the +inventory) but ships no agent-guidance doc — neither `AGENTS.md` (the cross-vendor +convention) nor `CLAUDE.md` — at any depth. Fires once per scan +(`repo_has_sdk_in_code: [langchain]` AND NOT `repo_component_present: [agents_md, +claude_md]`). It carries no `language` field, so it fires for both Python and +TypeScript LangChain repos. + +--- + +## Why a missing guidance doc matters for a LangChain repo + +An editing coding agent reads `AGENTS.md` before it acts. With neither file present, +any agent that opens this repo has no project-specific guidance on the choices that +make LangChain code safe or unsafe, and LangChain offers an unusually wide menu of +those choices: + +- which agent constructor to use — `create_react_agent` (deprecated), the v1 + `create_agent`, the legacy `AgentExecutor`, or a raw `StateGraph`; +- how tools must be defined (typed `args_schema`, descriptions) and guarded; +- whether the REPL/shell built-ins (`PythonREPLTool`, `ShellTool`) are permitted at + all, and behind what sandbox/approval; +- the local test, lint, and build commands. + +Without that guidance, a generative agent reaches for the most-documented pattern — +often the deprecated one, or a REPL tool — and produces code that violates the +project's tool and agent contracts. That is a slow-acting excessive-agency risk +(LLM06): nothing in-tree teaches the next agent the local rules. + +--- + +## Rule-by-rule defense + +### LC-201 — LangChain project ships no agent-guidance doc (Severity: low, Confidence: 0.9, Fix type: config) + +**What we detect:** `SDKLangChain` in `SDKsDetected` and no `agents_md` or +`claude_md` component anywhere in the repo. + +**Why it is flaggable:** the absence is the signal; it is a hygiene gap, not a +runtime vulnerability. + +**Severity low:** advisory. **Confidence 0.9:** the check is a near-deterministic +file-presence test; the small residual is a repo that documents agent guidance under +a non-standard filename the component scan does not recognize. + +**Fix type — config:** adding a doc file is a repo-config change, not a code edit. + +--- + +## What this policy does not cover + +The *quality* of a present `AGENTS.md`/`CLAUDE.md` (any such file silences the +rule), guidance docs under non-standard names, and whether the documented +conventions are actually followed in code. + +--- + +## Recommendations beyond the fix + +Add an `AGENTS.md` at the repo root (a `CLAUDE.md` also satisfies the rule). State +which LangChain agent constructors the project uses and why, how tools must be +defined and guarded, whether the REPL/shell built-ins are permitted and behind what +gate, and the exact test, lint, and build commands. Keep it short and concrete so an +editing agent can act on it without re-deriving the conventions. diff --git a/docs/Policy/langchain/shell_safety.md b/docs/Policy/langchain/shell_safety.md new file mode 100644 index 0000000..cab569e --- /dev/null +++ b/docs/Policy/langchain/shell_safety.md @@ -0,0 +1,117 @@ +--- +policy_id: langchain_shell_safety +category: langchain +topic: shell_safety +rules: + - id: LC-003 + severity: high + confidence: 0.85 + scope: tool + fix_type: code + - id: LC-011 + severity: high + confidence: 0.85 + scope: tool + fix_type: code +references: [LLM06, LLM05] +--- + +# Policy Rationale: LangChain Shell Safety + +**Policy ID:** `langchain_shell_safety` +**File:** `langchain/shell_safety.yaml` +**Rules:** LC-003, LC-011 +**Severities:** high +**Fix types:** code +**References:** LLM06 (Excessive Agency), LLM05 (Improper Output Handling) + +> **Read [openai_sdk/shell_safety.md](../openai_sdk/shell_safety.md) for the full +> threat model.** This document covers the LangChain-specific differences only. + +--- + +## What this policy covers + +LangChain tools whose body spawns an OS process. Python (LC-003) uses the same +`has_shell_call` AST predicate as the OpenAI/ADK packs — a resolved callee of +`os.system`, `os.popen`, any `subprocess.*`, or any `os.spawn*`. TypeScript +(LC-011) reads the discovery-computed `shells_out` fact, set when a tool handler +calls a `child_process` primitive (`exec`, `execSync`, `spawn`, `fork`, …). + +For the Python factory forms (`StructuredTool.from_function(fn)`), discovery points +the tool at the wrapped function body, so the predicate scans the real +implementation, not the registration call site. + +--- + +## Why shell execution is a distinct concern in LangChain agents + +The mechanism is identical to the OpenAI case (the model selects the command; the +subprocess inherits the runtime's filesystem, environment, and credentials) — see +[openai_sdk/shell_safety.md](../openai_sdk/shell_safety.md#why-shell-execution-is-a-distinct-concern-in-agent-tools). + +The LangChain-specific sharpening: LangChain ships a first-class `ShellTool` +(recognized at agent scope by LC-101), so shelling out is a *normalized* pattern +in this ecosystem rather than an exception. A hand-rolled `subprocess.run(cmd, +shell=True)` inside a `@tool` carries the identical risk as `ShellTool` but with +none of its (minimal) guardrails, and it hides inside an ordinary-looking tool. In +a ReAct loop the command string is chosen by the model from tool output and prior +context, so a single injected instruction reaches the shell. + +--- + +## Rule-by-rule defense + +### LC-003 — Python tool body spawns a subprocess (Severity: high, Confidence: 0.85, Fix type: code) + +**What we detect:** a Python LangChain tool whose body invokes `os.system`, +`os.popen`, a `subprocess.*` function, or an `os.spawn*` function (predicate +`has_shell_call`, an AST callee walk, not a substring scan). + +**Why it is flaggable:** process spawn from a model-callable tool puts the OS shell +on the model's tool surface. The presence of the spawn is the signal; every +safeguard is bolted onto an inherently broad primitive. + +**Real-world consequence:** a `run(cmd)` tool forwarding a model string into +`subprocess.run(cmd, shell=True)` is one prompt injection from arbitrary command +execution with the agent's privileges. + +**Severity high:** the fix usually means removing the spawn or rearchitecting +behind a typed API. Not raised above high because the exposure depends on what the +caller does with the spawn. **Confidence 0.85:** the `subprocess.*` prefix +over-fires on the rare non-spawning helper (`subprocess.list2cmdline`), and +async/`pty` spawn primitives escape the body walk. + +### LC-011 — TypeScript tool body spawns a subprocess (Severity: high, Confidence: 0.85, Fix type: code) + +**What we detect:** a TS LangChain tool whose handler calls a `child_process` +primitive (the `shells_out` fact set by `tsHandlerFacts`). + +**Why it is flaggable / consequence:** identical to LC-003 in the Node runtime — a +model-chosen string reaching `exec`/`execSync` is a direct path from prompt +injection to RCE. + +**Severity high / Confidence 0.85:** same profile; the fact is set on the bare and +`child_process.`-qualified callee forms, and a spawn hidden behind a helper in +another module escapes it. + +--- + +## What this policy does not cover + +The same gaps as [openai_sdk/shell_safety.md](../openai_sdk/shell_safety.md#what-this-policy-does-not-cover): +`asyncio.create_subprocess_*`, `pty`/`pexpect`, `multiprocessing`, the `os.exec*` +family, and spawns wrapped behind a cross-module helper. Whether a given literal +command is safe is out of scope. The `ShellTool` built-in is flagged at agent +scope by LC-101, not here. + +--- + +## Recommendations beyond the fix + +The safe pattern — typed library API, argv list with `shell=False` (or +`execFile`/`spawn` with an argument array in TS), `timeout=`, sandboxing, dropped +env vars — is in +[openai_sdk/shell_safety.md](../openai_sdk/shell_safety.md#recommendations-beyond-the-fix). +Keep shell logic out of any agent-callable tool; if a command must run, gate it +behind a human-in-the-loop approval (a LangGraph `interrupt_before` breakpoint). diff --git a/docs/Policy/langchain/ssrf.md b/docs/Policy/langchain/ssrf.md new file mode 100644 index 0000000..a589e14 --- /dev/null +++ b/docs/Policy/langchain/ssrf.md @@ -0,0 +1,99 @@ +--- +policy_id: langchain_ssrf +category: langchain +topic: ssrf +rules: + - id: LC-005 + severity: high + confidence: 0.8 + scope: tool + fix_type: code + - id: LC-013 + severity: high + confidence: 0.8 + scope: tool + fix_type: code +references: [LLM06, LLM02] +--- + +# Policy Rationale: LangChain SSRF + +**Policy ID:** `langchain_ssrf` +**File:** `langchain/ssrf.yaml` +**Rules:** LC-005, LC-013 +**Severities:** high +**Fix types:** code +**References:** LLM06 (Excessive Agency), LLM02 (Sensitive Information Disclosure) + +> **Read [openai_sdk/ssrf.md](../openai_sdk/ssrf.md) for the full threat model.** +> This document covers the LangChain-specific differences only. + +--- + +## What this policy covers + +LangChain tools that issue an outbound HTTP request to a caller-controlled +(non-literal) URL. Python (LC-005) uses `has_dynamic_url_call` — an HTTP call +(`requests`/`httpx`/`urllib`/`aiohttp`, alias-resolved) whose first argument is not +a plain string literal. TypeScript (LC-013) reads the `dynamic_url` fact, set when a +`fetch`/`axios`/`got` call takes a non-literal URL. + +--- + +## Why a model-controlled URL is server-side request forgery + +The mechanism and the metadata-endpoint / internal-service impact are covered in +[openai_sdk/ssrf.md](../openai_sdk/ssrf.md). The LangChain-specific note: this +ecosystem ships a `RequestsToolkit` and a `Requests*` tool family whose docstrings +explicitly require `allow_dangerous_requests=True` precisely because they hand the +model an arbitrary-URL fetch. A hand-rolled `requests.get(url)` inside a `@tool` +reproduces that exposure without the explicit opt-in, so it reads as an ordinary +tool while granting the same SSRF primitive. The model — or a prompt injection in +content it already fetched — chooses the host (LLM06), reaching internal services +and credential endpoints an external caller could not (LLM02). + +--- + +## Rule-by-rule defense + +### LC-005 — Python tool fetches a caller-controlled URL (Severity: high, Confidence: 0.8, Fix type: code) + +**What we detect:** a Python LangChain tool that makes an HTTP call whose URL +argument is a parameter, an f-string with substitution, or another non-literal +(predicate `has_dynamic_url_call`). + +**Why it is flaggable / consequence:** the destination is model-controlled, so the +tool can be driven to `http://169.254.169.254/...` or a localhost admin port the +agent host can see. Classic SSRF handed to the model. + +**Severity high:** the fix is an allow-list / SSRF guard, a real code change. **Confidence +0.8:** an internal-only deployment with no reachable sensitive endpoints lowers the +real-world impact, so the confidence is a notch below the shell/code rules. + +### LC-013 — TypeScript tool fetches a caller-controlled URL (Severity: high, Confidence: 0.8, Fix type: code) + +**What we detect:** a TS LangChain tool calling `fetch`/`axios`/`got` with a +non-literal URL (the `dynamic_url` fact). + +**Why it is flaggable / consequence:** identical in the Node runtime. + +**Severity high / Confidence 0.8:** same profile as LC-005. + +--- + +## What this policy does not cover + +Whether an allow-list is actually enforced downstream, redirects into private +ranges, DNS-rebinding, and URLs assembled across function boundaries. A literal +base URL with only a model-supplied path is treated as safe by the dynamic-URL +check even though path traversal on the target may still matter. + +--- + +## Recommendations beyond the fix + +Validate the URL against a host allow-list, reject private and link-local ranges +(and redirects into them), and never pass a raw model-supplied URL to the HTTP +client. If the tool talks to one service, hard-code the base URL and accept only a +path/query from the model. The full safe pattern is in +[openai_sdk/ssrf.md](../openai_sdk/ssrf.md#recommendations-beyond-the-fix). diff --git a/docs/Policy/langchain/tool_behavior.md b/docs/Policy/langchain/tool_behavior.md new file mode 100644 index 0000000..afd8a68 --- /dev/null +++ b/docs/Policy/langchain/tool_behavior.md @@ -0,0 +1,110 @@ +--- +policy_id: langchain_tool_behavior +category: langchain +topic: tool_behavior +rules: + - id: LC-006 + severity: medium + confidence: 0.8 + scope: tool + fix_type: config + - id: LC-014 + severity: medium + confidence: 0.8 + scope: tool + fix_type: config +references: [LLM05, LLM06] +--- + +# Policy Rationale: LangChain Tool Behavior + +**Policy ID:** `langchain_tool_behavior` +**File:** `langchain/tool_behavior.yaml` +**Rules:** LC-006, LC-014 +**Severities:** medium +**Fix types:** config +**References:** LLM05 (Improper Output Handling), LLM06 (Excessive Agency) + +--- + +## What this policy covers + +The LangChain-specific `return_direct` flag (`returnDirect` in TypeScript). When a +tool sets it true, LangChain returns the tool's raw output straight to the caller +and **halts the agent loop** — the model never observes the result. Discovery +captures the flag into `ToolDef.Config` (from the `@tool` decorator kwargs, the +`StructuredTool` constructor, or the TS `tool()` config object), and the rules +match it with `tool_decorator_kwarg_value`. + +This is a behavioral configuration check, not a body check — hence `fix_type: +config`. + +--- + +## Why returning directly is a reliability and safety concern + +The agent loop's value is that the model *observes* each tool result and decides +what to do next — including validating it, summarizing it, retrying on error, and +running any output guardrail or formatting step. `return_direct=True` removes that +step entirely: + +- **Improper output handling (LLM05):** whatever the tool returns — a raw stack + trace, an unsanitized chunk of fetched web content, a database row containing + secrets — is handed to the user verbatim. No model step and no post-tool + guardrail runs to redact or reshape it. If the tool fetches external content, + this is also a stored-prompt-injection delivery path straight to the user. +- **Broken control flow (LLM06):** any plan that expected the model to act on the + tool result silently stops. A multi-step task that calls a "search" tool with + `return_direct=True` ends at the search results, never reaching the synthesis the + user asked for. + +`return_direct` has legitimate uses (a terminal "hand off to human" tool), which is +why this is medium, not high — but it is frequently set without appreciating that +it disables the very loop that makes the tool safe to expose. + +--- + +## Rule-by-rule defense + +### LC-006 — Python tool returns its output directly (Severity: medium, Confidence: 0.8, Fix type: config) + +**What we detect:** a Python LangChain tool whose captured config has +`return_direct` equal to `True` (predicate `tool_decorator_kwarg_value`, kwarg +`return_direct`, value `True`). Covers the `@tool(return_direct=True)` decorator and +the `StructuredTool(..., return_direct=True)` constructor. + +**Why it is flaggable / consequence:** as above — the model is bypassed and raw +output reaches the user, breaking validation, guardrails, and multi-step plans. + +**Severity medium:** real reliability/exposure impact, but it is sometimes +intentional, so it is a finding to review rather than a defect to remove on sight. +**Confidence 0.8:** the deliberate "terminal tool" use is a genuine false-positive +class. + +### LC-014 — TypeScript tool returns its output directly (Severity: medium, Confidence: 0.8, Fix type: config) + +**What we detect:** a TS LangChain tool whose config has `returnDirect: true` +(captured into `ToolDef.Config` by discovery). + +**Why it is flaggable / consequence:** identical to LC-006 in LangChain.js. + +**Severity medium / Confidence 0.8:** same profile. + +--- + +## What this policy does not cover + +`return_direct` set dynamically (a computed expression rather than a literal), +`response_format="content_and_artifact"` (a related but distinct output-shape +flag), and the *content* of what a direct-returning tool emits — the rule flags the +control-flow change, not the specific data exposed. + +--- + +## Recommendations beyond the fix + +Leave `return_direct` / `returnDirect` at its default (false) unless you +specifically intend to short-circuit the agent. If you do, treat the tool's output +as untrusted user-facing data: sanitize and shape it inside the tool, since no +model step or guardrail runs after it. For a "final answer" pattern, prefer a +structured response the model emits after observing the tool, not a raw passthrough. diff --git a/docs/Policy/langchain/tool_definition.md b/docs/Policy/langchain/tool_definition.md new file mode 100644 index 0000000..a39823d --- /dev/null +++ b/docs/Policy/langchain/tool_definition.md @@ -0,0 +1,128 @@ +--- +policy_id: langchain_tool_definition +category: langchain +topic: tool_definition +rules: + - id: LC-001 + severity: low + confidence: 0.8 + scope: tool + fix_type: code + - id: LC-002 + severity: medium + confidence: 0.85 + scope: tool + fix_type: code + - id: LC-010 + severity: low + confidence: 0.8 + scope: tool + fix_type: code +references: [LLM06, LLM09] +--- + +# Policy Rationale: LangChain Tool Definition Hygiene + +**Policy ID:** `langchain_tool_definition` +**File:** `langchain/tool_definition.yaml` +**Rules:** LC-001, LC-002, LC-010 +**Severities:** low, medium +**Fix types:** code +**References:** LLM06 (Excessive Agency), LLM09 (Misinformation) + +--- + +## What this policy covers + +The two pieces of metadata a model relies on to call a LangChain tool correctly: +its **description** and its **parameter schema**. LangChain surfaces both to the +model verbatim — the description as the tool's purpose, the schema (Pydantic +`args_schema` or the wrapped function's type hints; in TS the Zod/JSON `schema`) +as the argument contract. When either is missing, the model is choosing and +populating tool calls blind. + +Discovery recognizes the `@tool` decorator and the `StructuredTool` / `Tool` +factories (Python), and the `tool()` factory plus `DynamicStructuredTool` / +`DynamicTool` (TypeScript). The `@tool` decorator is shared with the Claude Agent +SDK; Trustabl disambiguates by import, so a langchain-importing file routes `@tool` +to this pack and a Claude-SDK file does not. + +--- + +## Why tool metadata is a reliability and safety concern + +A tool the model cannot understand is a tool it calls at the wrong time, with the +wrong arguments, or not at all (LLM09 — the model acts on a wrong understanding of +what the tool does). In an agent loop that compounds: a mis-called tool returns an +error or a wrong result, the model re-plans on bad information, and the loop +either fails or takes an unintended action (LLM06). Description and schema quality +is the cheapest, highest-leverage lever on agent reliability. + +--- + +## Rule-by-rule defense + +### LC-001 — Tool has no description (Severity: low, Confidence: 0.8, Fix type: code) + +**What we detect:** a discovered Python LangChain tool whose `ToolDef.Description` +is empty — no `@tool` docstring, no `StructuredTool` `description=`. Predicate +`has_docstring: false`. + +**Why it is flaggable:** LangChain defaults a tool's description to the wrapped +function's docstring. With none, the model sees only a bare name. This is the +single highest-leverage authoring fix for tool reliability. + +**Real-world consequence:** a tool named `search` with no description is invoked +for the wrong queries, or skipped in favor of a better-described peer; the model +has no basis to choose. + +**Severity low:** a missing description degrades reliability but is not itself a +security defect. **Confidence 0.8:** a tool may legitimately be self-describing by +name in trivial cases, so a small false-positive rate is expected. + +### LC-002 — Tool parameters are not type-annotated (Severity: medium, Confidence: 0.85, Fix type: code) + +**What we detect:** a Python LangChain tool that has parameters but none are +type-annotated and no `args_schema` is supplied. Predicate `all: [has_params: +true, has_typed_params: false]` — gated on `has_params` so a zero-argument tool +does not fire. + +**Why it is flaggable:** LangChain derives the argument JSON schema from type hints +(or an `args_schema` model). Untyped parameters produce an underspecified schema; +the model passes wrong-typed arguments that LangChain rejects at validation time — +a silent per-call failure tax. + +**Severity medium:** a step above missing description because it breaks tool calls +mechanically, not just stylistically. **Confidence 0.85:** the few false positives +are tools that intend a single free-form string argument. + +### LC-010 — TypeScript tool has no description (Severity: low, Confidence: 0.8, Fix type: code) + +**What we detect:** a discovered TypeScript LangChain tool whose `description` field +is empty. Same `has_docstring: false` predicate, reading `ToolDef.Description` +populated from the `tool()` / `DynamicStructuredTool` config. + +**Why it is flaggable:** LangChain.js takes the description as an explicit config +field with no docstring fallback, so omitting it is a silent gap rather than a +syntax error — the model gets no signal about the tool's purpose. + +**Severity low / Confidence 0.8:** same profile as LC-001. + +--- + +## What this policy does not cover + +The *quality* of a present description (a one-word description satisfies the +check), descriptions assembled at runtime, and class-based tools +(`class X(BaseTool)` / `extends StructuredTool`), which are a documented discovery +gap. Argument typing via runtime validators other than Pydantic/Zod is not +recognized. + +--- + +## Recommendations beyond the fix + +Write the description for the model: one sentence naming what the tool does, the +inputs it expects, and what it returns. Annotate every parameter with a concrete +type or an `args_schema` Pydantic model (Zod schema in TS). Treat both as part of +the tool's public contract, reviewed like any API surface. diff --git a/langchain/POLICY_INDEX.md b/langchain/POLICY_INDEX.md new file mode 100644 index 0000000..561f0aa --- /dev/null +++ b/langchain/POLICY_INDEX.md @@ -0,0 +1,24 @@ + +# LangChain / LangGraph policy index + +15 rules — 11 tool · 3 agent · 1 repo + +Risk score = `severity_weight × confidence × 100` (engine formula; weights: low=0.15, medium=0.40, high=0.70). Higher = worse. + +| | Id | SDK/ADK | Scope | Applies To | Policy | Severity | Confidence | Risk | Source | +| -- | ------ | --------- | ----- | ----------------------------------------- | -------------------------------------------------------------------------- | -------- | ---------- | ---- | ----------------------------------------------------------------------------------------------------------- | +| 1 | LC-001 | LangChain | tool | langchain_tool | LangChain tool has no description | low | 0.80 | 12.0 | [tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_definition.yaml) | +| 2 | LC-002 | LangChain | tool | langchain_tool | LangChain tool parameters are not type-annotated | medium | 0.85 | 34.0 | [tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_definition.yaml) | +| 3 | LC-003 | LangChain | tool | langchain_tool | LangChain tool body spawns a subprocess | high | 0.85 | 59.5 | [shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/shell_safety.yaml) | +| 4 | LC-004 | LangChain | tool | langchain_tool | LangChain tool body evaluates dynamic code | high | 0.85 | 59.5 | [code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/code_execution.yaml) | +| 5 | LC-005 | LangChain | tool | langchain_tool | LangChain tool fetches a caller-controlled URL (SSRF) | high | 0.80 | 56.0 | [ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/ssrf.yaml) | +| 6 | LC-006 | LangChain | tool | langchain_tool | LangChain tool returns its output directly, bypassing the model | medium | 0.80 | 32.0 | [tool_behavior.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_behavior.yaml) | +| 7 | LC-010 | LangChain | tool | langchain_tool | TypeScript LangChain tool has no description | low | 0.80 | 12.0 | [tool_definition.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_definition.yaml) | +| 8 | LC-011 | LangChain | tool | langchain_tool | TypeScript LangChain tool body spawns a subprocess | high | 0.85 | 59.5 | [shell_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/shell_safety.yaml) | +| 9 | LC-012 | LangChain | tool | langchain_tool | TypeScript LangChain tool evaluates dynamic code | high | 0.85 | 59.5 | [code_execution.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/code_execution.yaml) | +| 10 | LC-013 | LangChain | tool | langchain_tool | TypeScript LangChain tool fetches a caller-controlled URL (SSRF) | high | 0.80 | 56.0 | [ssrf.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/ssrf.yaml) | +| 11 | LC-014 | LangChain | tool | langchain_tool | TypeScript LangChain tool returns its output directly, bypassing the model | medium | 0.80 | 32.0 | [tool_behavior.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/tool_behavior.yaml) | +| 12 | LC-101 | LangChain | agent | langchain_agent, langchain_agent_executor | LangChain agent wires a code-execution or shell built-in tool | high | 0.85 | 59.5 | [agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/agent_safety.yaml) | +| 13 | LC-102 | LangChain | agent | langchain_agent_executor | LangChain AgentExecutor has no max_iterations limit | medium | 0.80 | 32.0 | [agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/agent_safety.yaml) | +| 14 | LC-111 | LangChain | agent | langchain_agent_executor | TypeScript LangChain AgentExecutor has no maxIterations limit | medium | 0.80 | 32.0 | [agent_safety.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/agent_safety.yaml) | +| 15 | LC-201 | LangChain | repo | langchain | LangChain project ships no agent-guidance doc (AGENTS.md/CLAUDE.md) | low | 0.90 | 13.5 | [repo_hygiene.yaml](https://github.com/trustabl/trustabl-rules/blob/main/langchain/repo_hygiene.yaml) | diff --git a/tools/gen_index.py b/tools/gen_index.py index 6b10aea..c6becaf 100644 --- a/tools/gen_index.py +++ b/tools/gen_index.py @@ -32,13 +32,14 @@ GH_BASE = "https://github.com/trustabl/trustabl-rules/blob/main/" GENERATED_MARKER = "" -SDK_ORDER = ["claude_sdk", "openai_sdk", "google_adk", "mcp"] -SDK_LABEL = {"claude_sdk": "Claude SDK", "openai_sdk": "OpenAI SDK", "google_adk": "Google ADK", "mcp": "MCP"} +SDK_ORDER = ["claude_sdk", "openai_sdk", "google_adk", "mcp", "langchain"] +SDK_LABEL = {"claude_sdk": "Claude SDK", "openai_sdk": "OpenAI SDK", "google_adk": "Google ADK", "mcp": "MCP", "langchain": "LangChain"} SDK_FULL = { "claude_sdk": "Claude Agent SDK", "openai_sdk": "OpenAI Agents SDK", "google_adk": "Google ADK", "mcp": "Model Context Protocol", + "langchain": "LangChain / LangGraph", } SCOPE_ORDER = ["tool", "agent", "subagent", "repo"]