Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,13 @@ product.
notes, examples, or work-in-progress `.yaml` files inline — they will fail
the loader. Markdown docs (`README.md`, `CLAUDE.md`, per-pack READMEs) are
fine; the loader only reads `.yaml`.
- Not the home of compliance crosswalks. Control mappings (rule ID to
NIST/ISO/SOC 2/PCI/EU AI Act controls) live in the **engine** repo at
`internal/compliance/mappings/` and are embedded in the binary. They do not
belong here: this repo is **public**, compliance is a Guard-only surface (the
open-source scanner ships no `compliance` command), and the engine's rule
loader skips a `mappings/` subtree anyway — so a crosswalk here is exposed to
everyone and read by no one. Engine builds released before that skip existed
walk every `*.yaml` in the pack and hard-fail on a non-policy file, so if a
`mappings/` directory ever reappears here it must never contain `.yaml`.
- Not the home of the schema or predicates. Those live in the engine repo.
4 changes: 2 additions & 2 deletions claude_sdk/agent_safety.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ rules:

- id: CSDK-103
title: AgentDefinition sets permissionMode to bypassPermissions
severity: high
severity: critical
confidence: 0.9
language: python
applies_to:
Expand Down Expand Up @@ -145,7 +145,7 @@ rules:

- id: CSDK-120
title: TypeScript AgentDefinition sets permissionMode to bypassPermissions
severity: high
severity: critical
confidence: 0.9
language: typescript
applies_to:
Expand Down
4 changes: 2 additions & 2 deletions claude_sdk/repo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ policy:
rules:
- id: CSDK-201
title: Project default permission mode bypasses approvals
severity: high
severity: critical
confidence: 0.9
applies_to:
- claude_sdk
Expand All @@ -35,7 +35,7 @@ rules:

- id: CSDK-202
title: Session permission mode bypasses approvals
severity: high
severity: critical
confidence: 0.9
applies_to:
- claude_sdk
Expand Down
2 changes: 1 addition & 1 deletion google_adk/builtin_tools.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ policy:
rules:
- id: ADK-008
title: Agent grants the bash tool with no restrictive command policy
severity: high
severity: critical
confidence: 0.75
language: python
applies_to:
Expand Down
2 changes: 1 addition & 1 deletion langchain/agent_safety.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ policy:
rules:
- id: LC-101
title: LangChain agent wires a code-execution or shell built-in tool
severity: high
severity: critical
confidence: 0.85
language: python
applies_to:
Expand Down
99 changes: 99 additions & 0 deletions openai_sdk/agent_safety.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,42 @@ rules:
privileged tools are needed but sandboxing is impractical, document
the decision and acknowledge the elevated risk explicitly.

- id: OAI-107
title: Handoff-target agent wires shell or filesystem-touching tools
severity: high
confidence: 0.85
language: python
applies_to:
- openai_agent
- openai_sandbox_agent
scope: agent
match:
all:
- agent_is_subagent_of_any: true
- agent_uses_tool_kind: [shell_invocation]
explanation: >
This agent is the target of a handoff (it appears in another agent's
handoffs=[...]) AND is wired with tools that execute shell commands or
touch the filesystem. In the OpenAI Agents SDK, input_guardrails run
only on the agent that first receives the user input — a handoff target
never runs its own input_guardrails on the handed-off turn. A parent can
therefore route around its own guardrails by delegating to this child and
asking it to run the shell-touching tool the parent would have screened.
The child's privileged tools then execute on input that no guardrail
ever inspected. This is why the rule does not require the child's
input_guardrails to be empty: even a child that declares guardrails does
not run them on the delegated turn, so the shell exposure is the hazard
regardless.
fix: >
Either remove the shell or filesystem-touching tools from this handoff
target, or move the privileged tools up to the top-level agent that
receives user input — where its input_guardrails actually run — and have
that agent do the work instead of delegating it. If the handoff must
stay, validate the handoff payload before it reaches the child (for
example with an @input_guardrail on the parent and an input_filter on
the handoff), since the SDK will not run the child's own guardrails on
the delegated turn.

- id: OAI-109
title: Agent uses WebSearchTool without input_guardrails
severity: high
Expand Down Expand Up @@ -193,3 +229,66 @@ rules:
wire it via `inputGuardrails: [...]` on the `Agent({...})` constructor. Pin
MCP servers to trusted endpoints and treat web and file results as untrusted
data.

- id: OAI-112
title: Guarded agent transitively wields shell through its handoff chain
severity: high
confidence: 0.6
language: python
applies_to:
- openai_agent
- openai_sandbox_agent
scope: agent
match:
all:
- agent_kwarg_present:
- input_guardrails
- transitive_capability_exceeds_direct:
- shell
explanation: >
This agent declares input_guardrails but delegates — directly or through
a chain of handoffs — to an agent whose tools execute shell commands, a
capability this agent does not wield itself. In the OpenAI Agents SDK,
input_guardrails run only on the agent that first receives the user
input, and a handoff target never runs its own input_guardrails on the
delegated turn. The guardrails here therefore create false confidence:
the shell-executing turn happens downstream, on a payload the handoff
may have transformed, with no guardrail in front of it.
fix: >
Treat the handoff chain as part of this agent's attack surface. Either
move the shell-wielding work up to this agent, where its guardrails
actually run; remove the shell tools from the downstream agent; or
constrain the delegated payload explicitly — an input_filter on the
handoff plus tool-level validation on the downstream agent.

- id: OAI-113
title: Unguarded agent's handoff chain reaches shell execution
severity: medium
confidence: 0.6
language: python
applies_to:
- openai_agent
- openai_sandbox_agent
scope: agent
match:
all:
- not:
agent_kwarg_present:
- input_guardrails
- transitive_capability_exceeds_direct:
- shell
explanation: >
This agent declares no input_guardrails and delegates, directly or
through a chain of handoffs, to an agent whose tools execute shell
commands — a capability this agent does not wield itself. If this agent
is where user input enters, nothing screens that input anywhere on a
delegation path that ends in shell execution: input_guardrails run only
on the first agent in the run, and handoff targets never run their own
on delegated turns. The chain makes the exposure easy to miss — each
agent looks harmless in isolation.
fix: >
Add input_guardrails to this agent so the entry point of the delegation
chain screens input before any downstream shell tool can act on it, and
review whether the downstream agent's shell access is needed at all.
The downstream agent's own configuration is flagged separately by the
direct shell-tool rules.
27 changes: 27 additions & 0 deletions openai_sdk/tool_definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,30 @@ rules:
Provide a concise `description` string in the `tool({...})` options stating
what the tool does and when the model should call it. The description is the
model's primary routing signal alongside the tool name.

- id: OAI-025
title: Tool is defined but never referenced anywhere in the repo
severity: low
confidence: 0.5
language: python
applies_to:
- openai_tool
scope: tool
match:
reachability_is:
- unreachable
explanation: >
This @function_tool-decorated function is never referenced anywhere in
the repo's Python code — it appears in no Agent's tools=[...], no
handoff, and no call site. Trustabl's call-graph liveness marks a tool
unreachable only when nothing references its name at all, so this is
dead capability code: it is not exposed to any model today, but it
carries tool-grade capability (and drifts unreviewed) until a later
refactor wires it in. Dead tool definitions also misdirect review
effort toward code no agent can call.
fix: >
Delete the tool definition, or wire it into the intended agent's
tools=[...] list deliberately. If the tool is dispatched dynamically
(getattr, a string-keyed registry), static liveness cannot see that
reference — prefer a direct name reference so both the model wiring
and this analysis can track it.
Loading