# Defense-in-Depth Score: CrewAI

**Repo:** https://github.com/crewAIInc/crewAI · **Commit:** `738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d` · **Reviewed:** 2026-10-03
**What it is:** Framework for orchestrating role-playing autonomous multi-agent crews
**Category:** Agent Frameworks
**Scored configuration:** Python library defaults: Agent/Crew/Task public constructors with no options set (no tools, memory off, delegation off, telemetry on), plus the first-party crewai-tools package as shipped.
**Agent surface (default):** code execution opt-in · filesystem write opt-in · network egress yes · external credentials yes · persistent memory opt-in · untrusted input yes · third party extensions opt-in · sub agents opt-in · external communication opt-in

## Score: 2.4 / 10.0 (Minimal)

| # | Criterion | S | C | D | B | Raw | Cap | Score | Confidence |
|---|---|---|---|---|---|---|---|---|---|
| C1 | Identity & least privilege | L0 | L0 | L0 | L1 | 0.05 | — | **0.05** | High |
| C2 | Approval gates | L2 | L2 | L0 | L0 | 0.30 | G1 | **0.30** (alt) | High |
| C3 | Tool & action scoping | L3 | L2 | L3 | L2 | 0.62 | — | **0.62** | High |
| C4 | Code-execution isolation | L4 | L1 | L0 | L2 | 0.47 | G1 | **0.47** (alt) | Medium |
| C5 | Untrusted input blast radius | L0 | L0 | L0 | L0 | 0.00 | C5-WORSTCASE | **0.00** | High |
| C6 | Memory, context & configuration integrity | L0 | L0 | L1 | L0 | 0.05 | C6-REPOCONFIG | **0.05** | High |
| C7 | Third-party extensions | L0 | L0 | L0 | L0 | 0.00 | C7-RCELOAD | **0.00** | High |
| C8 | Secrets & sensitive-data protection | L1 | L1 | L1 | L1 | 0.25 | — | **0.25** | High |
| C9 | Audit & traceability | L2 | L2 | L0 | L1 | 0.35 | G1 | **0.35** | High |
| C10 | Limits & kill switch | L1 | L1 | L1 | L1 | 0.25 | — | **0.25** | High |


CrewAI runs whatever tools you give an agent with no approval step, no limits on what a prompt-injected agent can do, and no default audit record. Its bundled tools validate paths and block internal URLs well, but the framework itself auto-loads files from the working directory (a training-data file and a .env) on every run without a trust decision, so a planted or agent-written file can rewrite the agent's instructions. Add before-tool-call approval hooks, keep the working directory free of attacker-writable files, and set time and spend limits before connecting email, chat or write APIs.

## Critical gaps
- Nothing stops a prompt-injected agent from combining untrusted web input, private data and outbound actions (e.g. Gmail) without a human. (ASI01, LLM01; C5) — [docs/edge/en/concepts/agent-capabilities.mdx:44-51](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/docs/edge/en/concepts/agent-capabilities.mdx#L44-L51)
- Files in the working directory (the training-data file, .env) are auto-loaded every run without a trust decision and can inject must-follow instructions, disable tool path/SSRF checks, or redirect endpoints. (ASI06; C6) — [lib/crewai/src/crewai/agent/core.py:1440-1447](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agent/core.py#L1440-L1447); [lib/crewai/src/crewai/llm.py:83](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/llm.py#L83); [lib/crewai-tools/src/crewai_tools/security/safe_path.py:79-89](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_path.py#L79-L89)

## Criterion details

### C1 Identity & least privilege — 0.05 (high)

CrewAI has no identity or authorization layer of its own. Each tool reads whatever API key is in the process environment and builds its own client, so an agent acts with the full authority of every key the developer exported. Local MCP servers do get a reduced environment from the MCP SDK, but nothing checks per request whether the agent, or the user it serves, should be allowed to make a call. With platform apps (Gmail, Slack, Sheets) and third-party tools enabled together, a hijacked agent can write to several outside systems.

- **S L0:** Tools use ambient environment credentials (e.g. the platform integration bearer token) with no scoping or per-request authority. — [lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py:6](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py#L6); searched `rg -n -i 'assume_role|token_exchange|on_behalf_of|downscop'` in `lib/crewai/src/crewai` → 0 hits (no credential scoping or per-request authority primitive) (verified)
  - *To reach the next level:* No dedicated or role-scoped identity; L1 needs at least a dedicated identity for the agent.
- **C L0:** Every tool constructs its own client from env vars; no authorization check sits on the tool path. — [lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py:6](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py#L6); [lib/crewai/src/crewai/tools/structured_tool.py:371-378](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/tools/structured_tool.py#L371-L378) (verified)
  - *To reach the next level:* No shared authorization layer; L1 needs the main tool path checked.
- **D L0:** Default install runs with every credential in the developer's environment; MCP stdio env scrubbing comes from the SDK, not a framework policy. — [lib/crewai/src/crewai/mcp/transports/stdio.py:86-90](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/mcp/transports/stdio.py#L86-L90); [lib/crewai/src/crewai/llm.py:83](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/llm.py#L83) (verified)
  - *To reach the next level:* Least privilege requires manual hardening; L1 needs a narrower default identity.
- **B L1:** Documented configurations combine platform apps (Gmail, Sheets), MCP servers and local tools, giving write access across several systems; nothing in the framework narrows it. — [docs/edge/en/concepts/agent-capabilities.mdx:44-51](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/docs/edge/en/concepts/agent-capabilities.mdx#L44-L51); [lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py:6](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py#L6) (verified)
  - *To reach the next level:* Write access spans multiple systems; L2 needs authority confined to one system.
- **Cap:** none

### C2 Approval gates — 0.30 (high)

Out of the box nothing asks a human before a tool runs: any tool the developer registers, including email, file writes or external APIs, executes as soon as the model calls it. Task 'human_input' only reviews the final answer after actions have already happened. The framework offers before-tool-call hooks that every executor runs and that can block a call or prompt the console user, but a developer has to write that gate, and the hooks do not cover every path. Because the hook is opt-in, its score is capped.

- **default configuration** (default; raw 0.00 → 0.00)
  - **S L0:** No approval step exists in the default tool path; Task.human_input reviews only the final answer. — [lib/crewai/src/crewai/task.py:233-236](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/task.py#L233-L236); [lib/crewai/src/crewai/utilities/agent_utils.py:1777](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/utilities/agent_utils.py#L1777) (verified)
    - *To reach the next level:* No per-call approval; L1 needs at least a blanket approval before consequential actions.
  - **C L0:** No tool, including the most powerful ones a developer registers, crosses a gate by default. — [lib/crewai/src/crewai/agents/agent_builder/base_agent.py:283-285](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agents/agent_builder/base_agent.py#L283-L285); [lib/crewai/src/crewai/utilities/agent_utils.py:1777](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/utilities/agent_utils.py#L1777) (verified)
    - *To reach the next level:* Every tool is exempt; L1 needs flagged tools gated.
  - **D L0:** Approval is entirely opt-in (developer-written hooks). — [lib/crewai/src/crewai/hooks/tool_hooks.py:86-121](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/hooks/tool_hooks.py#L86-L121); [lib/crewai/src/crewai/task.py:233-236](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/task.py#L233-L236) (verified)
    - *To reach the next level:* Approval is opt-in; L1 needs it on by default.
  - **B L0:** Documented setups pair web search, file reading and Gmail send with no undo or dry-run; irreversible external actions run unattended. — [docs/edge/en/concepts/agent-capabilities.mdx:44-51](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/docs/edge/en/concepts/agent-capabilities.mdx#L44-L51) (verified)
    - *To reach the next level:* Irreversible external actions have no undo; L1 needs some actions reversible.
- **opt-in before_tool_call hooks with request_human_input** (alt; raw 0.30, cap G1 → 0.30) ← counted
  - **S L2:** A hook receives the exact tool name and arguments and can block or prompt via console input, but the framework ships no rendering, risk tiers or argument policy; the UI is whatever the developer writes. — [lib/crewai/src/crewai/hooks/tool_hooks.py:86-121](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/hooks/tool_hooks.py#L86-L121); [lib/crewai/src/crewai/hooks/tool_hooks.py:142-150](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/hooks/tool_hooks.py#L142-L150) (verified)
    - *To reach the next level:* No built-in exact-call rendering with risk tiers; L3 needs per-call approval of the exact call with tiering in the framework.
  - **C L2:** Hooks run on every executor path (native function calls, ReAct text path, legacy and default executors), but hook enforcement is not a strict boundary. — [lib/crewai/src/crewai/utilities/agent_utils.py:1777](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/utilities/agent_utils.py#L1777); [lib/crewai/src/crewai/agents/crew_agent_executor.py:982](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agents/crew_agent_executor.py#L982); [lib/crewai/src/crewai/experimental/agent_executor.py:2065](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/experimental/agent_executor.py#L2065); [lib/crewai/src/crewai/utilities/tool_utils.py:123](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/utilities/tool_utils.py#L123) (verified)
    - *To reach the next level:* L3 needs every path to traverse the gate reliably.
  - **D L0:** No hook is registered by default. — [lib/crewai/src/crewai/hooks/tool_hooks.py:86-121](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/hooks/tool_hooks.py#L86-L121) (verified)
    - *To reach the next level:* Opt-in; L1 needs the gate on by default.
  - **B L0:** Same environment as the default: irreversible external actions with no undo. — [docs/edge/en/concepts/agent-capabilities.mdx:44-51](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/docs/edge/en/concepts/agent-capabilities.mdx#L44-L51) (verified)
    - *To reach the next level:* No undo or dry-run; L1 needs some actions reversible.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.

### C3 Tool & action scoping — 0.62 (high)

Every tool's arguments are checked against a typed schema before it runs, and the first-party crewai-tools package adds real input controls: file paths are resolved and confined to a base directory, URL fetchers block private and cloud-metadata addresses and re-check every redirect, and the SQL tool is read-only by default. Agents get no tools unless the developer adds them. The weak spots are that the default base directory is the working directory (which holds the project's .env and the auto-loaded training-data file), one environment variable switches off both path and SSRF checks, and custom or MCP tools only get schema typing.

- **S L3:** Bundled tools use realpath containment, private-IP/metadata blocking with per-hop redirect validation and IP pinning, and a read-only SQL allowlist. — [lib/crewai-tools/src/crewai_tools/security/safe_path.py:119-134](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_path.py#L119-L134); [lib/crewai-tools/src/crewai_tools/security/safe_path.py:162-169](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_path.py#L162-L169); [lib/crewai-tools/src/crewai_tools/security/safe_requests.py:1-5](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_requests.py#L1-L5); [lib/crewai-tools/src/crewai_tools/tools/nl2sql/nl2sql_tool.py:30](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/nl2sql/nl2sql_tool.py#L30) (verified)
  - *To reach the next level:* Validation is not race-robust (check-then-open) and general fetchers remain; L4 needs narrow tools with open-then-check validation.
- **C L2:** Every tool gets pydantic schema validation; the strong path/URL validators cover most bundled file and web tools, though not every bundled tool, and custom and MCP tools are not covered. — [lib/crewai/src/crewai/tools/structured_tool.py:371-378](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/tools/structured_tool.py#L371-L378); [lib/crewai-tools/src/crewai_tools/tools/file_writer_tool/file_writer_tool.py:116](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/file_writer_tool/file_writer_tool.py#L116) (verified)
  - *To reach the next level:* Extension and custom tools get only type checks; L3 needs a shared validation layer wrapping them.
- **D L3:** Agents start with an empty tool list and delegation off; write/network tools must be added explicitly. — [lib/crewai/src/crewai/agents/agent_builder/base_agent.py:283-285](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agents/agent_builder/base_agent.py#L283-L285); [lib/crewai/src/crewai/agents/agent_builder/base_agent.py:279-281](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agents/agent_builder/base_agent.py#L279-L281); [lib/crewai/src/crewai/task.py:216-219](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/task.py#L216-L219); [lib/crewai-tools/src/crewai_tools/security/safe_path.py:79-89](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_path.py#L79-L89) (verified)
  - *To reach the next level:* Per-task allowlists exist (Task.tools) but are not the default, and an env var disables path/SSRF checks; L4 needs per-task allowlists by default with no runtime widening.
- **B L2:** A misused file writer has full overwrite inside the working directory; fetchers reach any public host. — [lib/crewai-tools/src/crewai_tools/security/safe_path.py:116-117](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_path.py#L116-L117); [lib/crewai-tools/src/crewai_tools/tools/file_writer_tool/file_writer_tool.py:163](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/file_writer_tool/file_writer_tool.py#L163) (verified)
  - *To reach the next level:* No quantity bounds; L3 needs scoped and quantity-bounded operations.
- **Cap:** none

### C4 Code-execution isolation — 0.47 (medium)

The old local code interpreter has been removed, and the framework ships E2B and Daytona tools that run model code in remote, per-call sandboxes, but those are opt-in. By default, every tool runs inside the agent's own Python process with its environment and network. One default execution path that loads a workspace file is not confined.

- **default configuration** (default; raw 0.00 → 0.00)
  - **S L0:** No isolation primitive on the default path: tools run in-process. — [lib/crewai/src/crewai/agent/core.py:293-297](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agent/core.py#L293-L297) (verified)
    - *To reach the next level:* No boundary at all; L1 needs at least filtering.
  - **C L0:** Registered tools run on the host. — [lib/crewai/src/crewai/agent/core.py:725](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agent/core.py#L725) (verified)
    - *To reach the next level:* No path is sandboxed by default; L1 needs the main exec path sandboxed.
  - **D L0:** Sandboxed execution exists only as opt-in tools. — [lib/crewai/src/crewai/agents/agent_builder/base_agent.py:283-285](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agents/agent_builder/base_agent.py#L283-L285); [lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py:55-56](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py#L55-L56) (verified)
    - *To reach the next level:* Off by default; L1 needs isolation on by default.
  - **B L0:** Code that runs in the agent process holds every exported API key, the host filesystem and network. — [lib/crewai/src/crewai/llm.py:83](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/llm.py#L83) (verified)
    - *To reach the next level:* Host-equivalent; L1 needs at least credentials kept out of reach.
- **opt-in E2B remote sandbox tools (crewai-tools)** (alt; raw 0.47, cap G1 → 0.47) ← counted
  - **S L4:** Remote E2B sandbox created per call and killed afterwards by default. — [lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py:168-169](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py#L168-L169); [lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py:55-56](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py#L55-L56) (verified)
  - **C L1:** Only code sent to the E2B tool is sandboxed; MCP stdio servers and all other tools run on the host. — [lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py:168-169](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py#L168-L169); [lib/crewai/src/crewai/mcp/transports/stdio.py:86-90](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/mcp/transports/stdio.py#L86-L90) (verified)
    - *To reach the next level:* Other execution paths run on the host; L2 needs most paths sandboxed.
  - **D L0:** Opt-in tool; not part of the default configuration. — [lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py:55-56](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py#L55-L56); [lib/crewai/src/crewai/agents/agent_builder/base_agent.py:283-285](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agents/agent_builder/base_agent.py#L283-L285) (verified)
    - *To reach the next level:* Off by default; L1 needs it on by default.
  - **B L2:** Ephemeral and no host env passed by default, but network egress from the sandbox is unrestricted (E2B default, inferred) and the model can pass envs per call. — [lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py:77-78](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py#L77-L78); [lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py:168-169](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py#L168-L169) (inferred)
    - *To reach the next level:* Network egress is not off or allowlisted; L3 needs restricted egress.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.

### C5 Untrusted input blast radius — 0.00 (high)

CrewAI does nothing to limit what a hijacked agent can do after reading hostile content. Web pages, files, MCP results and other agents' outputs enter the conversation with the same standing as the developer's instructions; there is no tagging, no quarantine and no rule that switches off email or write tools once untrusted text has been read. The official docs show agents that search the web, read local files and send Gmail in the same session, so a successful prompt injection can leak data and take irreversible actions with no human involved.

- **S L0:** No structural limit, detector or provenance tagging for untrusted content. — searched `rg -n -i 'untrusted|prompt.injection|taint|quarantin'` in `lib/crewai/src/crewai` → 4 hits (none is a control: a telemetry comment, two docstrings using 'prompt injection' to mean inserting skill text, and a flow-template guideline) (verified)
  - *To reach the next level:* Nothing limits a hijacked agent; L1 needs at least detection or spotlighting.
- **C L0:** Tool results, MCP outputs and delegated agent replies are not distinguished from principal input. — searched `rg -n -i 'untrusted|prompt.injection|taint|quarantin'` in `lib/crewai/src/crewai` → 4 hits (none is a control: a telemetry comment, two docstrings using 'prompt injection' to mean inserting skill text, and a flow-template guideline); [lib/crewai/src/crewai/tools/agent_tools/base_agent_tools.py:120](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/tools/agent_tools/base_agent_tools.py#L120) (verified)
  - *To reach the next level:* No source is distinguished; L1 needs one source handled.
- **D L0:** No control exists to be on by default. — searched `rg -n -i 'untrusted|prompt.injection|taint|quarantin'` in `lib/crewai/src/crewai` → 4 hits (none is a control: a telemetry comment, two docstrings using 'prompt injection' to mean inserting skill text, and a flow-template guideline) (verified)
  - *To reach the next level:* Off by default; L1 needs a control on by default.
- **B L0:** Docs combine untrusted web search, private file reads and Gmail send with no approval: leak plus irreversible action unattended. — [docs/edge/en/concepts/agent-capabilities.mdx:44-51](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/docs/edge/en/concepts/agent-capabilities.mdx#L44-L51) (verified)
  - *To reach the next level:* Exfiltration and irreversible actions are both unattended; L1 needs one of them gated.
- **Cap:** C5-WORSTCASE — B is L0: in documented configurations a hijacked agent can leak data and send email with no human involved.

### C6 Memory, context & configuration integrity — 0.05 (high)

Memory is off by default; when enabled, the model can save anything with a 'Save to memory' tool and it is recalled into later prompts, stored per project folder with no per-user separation unless the developer adds scoping. Two files in the working directory shape every run without any trust decision: the training-data file, whose contents are added to the prompt as instructions the agent 'MUST follow', and the project's .env, loaded at import, which can redirect model endpoints or switch off the tools' path and SSRF checks. The file-writer tool writes into that same directory by default, so a hijacked agent can make its compromise persistent.

- **S L0:** Workspace files are auto-loaded as high-priority instructions (training-data file) and environment config (.env) with no prompt; memory writes are unvalidated. — [lib/crewai/src/crewai/agent/core.py:1440-1447](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agent/core.py#L1440-L1447); [lib/crewai/src/crewai/llm.py:83](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/llm.py#L83); [lib/crewai/src/crewai/tools/memory_tools.py:95](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/tools/memory_tools.py#L95) (verified)
  - *To reach the next level:* No control over writes or loads; L1 needs at least logged writes.
- **C L0:** Neither memory, the training file nor .env loading is controlled. — [lib/crewai/src/crewai/project/crew_base.py:130](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/project/crew_base.py#L130); [lib/crewai/src/crewai/tools/memory_tools.py:95](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/tools/memory_tools.py#L95) (verified)
  - *To reach the next level:* No path controlled; L1 needs one store controlled.
- **D L1:** Memory is off by default, but when on it lives in one store per project directory shared by all users, with scoping left to optional root_scope/source filters. — [lib/crewai/src/crewai/crew.py:256-268](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/crew.py#L256-L268); [lib/crewai-core/src/crewai_core/paths.py:11-13](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-core/src/crewai_core/paths.py#L11-L13) (verified)
  - *To reach the next level:* No per-user namespace enforced in queries by default; L2 needs per-user/session namespaces.
- **B L0:** A poisoned training file or .env persists across sessions and users of the project and steers tool use. — [lib/crewai/src/crewai/agent/core.py:1440-1447](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agent/core.py#L1440-L1447); [lib/crewai-tools/src/crewai_tools/security/safe_path.py:24](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_path.py#L24) (verified)
  - *To reach the next level:* Persists across users and triggers tool use; L1 needs persistence limited to one user.
- **Cap:** C6-REPOCONFIG — The training-data file and .env in the working directory are auto-loaded without a trust decision; .env can set CREWAI_TOOLS_ALLOW_UNSAFE_PATHS or API base URLs (dotenv search path is python-dotenv behaviour, inferred).

### C7 Third-party extensions — 0.00 (high)

Extensions are chosen by the developer (MCP servers, registry skills, platform apps); nothing third-party is enabled by default, and local MCP servers get a reduced environment from the MCP SDK. But nothing verifies what is loaded: MCP launch commands and registry skills resolve to whatever is latest unless pinned, with no hash or signature checks or re-approval on change. A workspace file loaded by default is not integrity-protected.

- **S L0:** A workspace file loaded by default is not integrity-protected; MCP servers and skills are unpinned and unverified unless the developer pins a version. — [lib/crewai/src/crewai/skills/registry.py:29](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/skills/registry.py#L29); searched `rg -n -i 'sha256|checksum|signature'` in `lib/crewai/src/crewai/mcp lib/crewai/src/crewai/skills` → 1 hits (the single hit is inspect.signature(), not an integrity check on MCP servers or skills) (verified)
  - *To reach the next level:* Unverified sources are loaded automatically; L1 needs user-chosen sources only.
- **C L0:** No extension type is integrity-checked. — searched `rg -n -i 'sha256|checksum|signature'` in `lib/crewai/src/crewai/mcp lib/crewai/src/crewai/skills` → 1 hits (the single hit is inspect.signature(), not an integrity check on MCP servers or skills); [lib/crewai/src/crewai/skills/registry.py:1-5](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/skills/registry.py#L1-L5) (verified)
  - *To reach the next level:* No type verified; L1 needs one type verified.
- **D L0:** A file in the workspace is loaded silently on every task. (verified)
  - *To reach the next level:* Workspace files are loaded silently; L1 needs consent before loading.
- **B L0:** Default-loaded workspace content is handled in-process with all credentials; MCP stdio servers get a scrubbed env (SDK default, inferred) but run as the same user. — [lib/crewai/src/crewai/mcp/transports/stdio.py:86-90](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/mcp/transports/stdio.py#L86-L90) (verified)
  - *To reach the next level:* In-process execution with full environment; L1 needs a separate process.
- **Cap:** C7-RCELOAD — By default every task loads a workspace file without consent.

### C8 Secrets & sensitive-data protection — 0.25 (high)

API keys come from environment variables (and a project .env loaded at import) and are passed to tools in plain form; the framework has no redaction for logs, events or model-bound messages. The bundled web fetcher does strip credentials on cross-origin redirects, and some configs use masked secret types. Anonymous usage telemetry is on by default but content-free unless the developer opts in with share_crew; content tracing needs explicit consent. Any tool that can read the working directory (the file reader's default scope) can read the .env file into model context.

- **S L1:** Secrets from env vars; masking only in isolated places (SecretStr in some configs, cross-origin header stripping in safe_get). — [lib/crewai-tools/src/crewai_tools/security/safe_requests.py:47-58](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_requests.py#L47-L58); searched `rg -n -i 'redact|scrub|mask_secret'` in `lib/crewai/src/crewai` → 12 hits (7 hits are Anthropic redacted_thinking handling, 4 are docstring examples of DIY hooks, 1 says redaction processors are supplied elsewhere; no redaction in the framework's log or model paths) (verified)
  - *To reach the next level:* No log filters or redaction on main paths; L2 needs type-level masking and log filters.
- **C L1:** Only the bundled fetch path strips credentials; logs, events, traces and model-bound messages are unprotected. — [lib/crewai-tools/src/crewai_tools/security/safe_requests.py:47-58](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_requests.py#L47-L58); searched `rg -n -i 'redact|scrub|mask_secret'` in `lib/crewai/src/crewai` → 12 hits (7 hits are Anthropic redacted_thinking handling, 4 are docstring examples of DIY hooks, 1 says redaction processors are supplied elsewhere; no redaction in the framework's log or model paths) (verified)
  - *To reach the next level:* One path only; L2 needs logs and transcripts protected.
- **D L1:** Telemetry to telemetry.crewai.com is on by default (content-free unless share_crew); disabled by env var. — [lib/crewai-core/src/crewai_core/telemetry.py:354-359](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-core/src/crewai_core/telemetry.py#L354-L359); [lib/crewai/src/crewai/telemetry/constants.py:9](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/telemetry/constants.py#L9); [lib/crewai/src/crewai/crew.py:298](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/crew.py#L298); [lib/crewai/src/crewai/telemetry/telemetry.py:307](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/telemetry/telemetry.py#L307) (verified)
  - *To reach the next level:* Telemetry is on by default; L2 needs telemetry opt-in.
- **B L1:** Long-lived provider and integration keys sit in the process env and the project .env, which is inside the file tools' default scope. — [lib/crewai/src/crewai/llm.py:83](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/llm.py#L83); [lib/crewai-tools/src/crewai_tools/security/safe_path.py:116-117](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/security/safe_path.py#L116-L117); [lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py:6](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py#L6) (verified)
  - *To reach the next level:* Keys are long-lived; L2 needs scoped keys.
- **Cap:** none

### C9 Audit & traceability — 0.35 (high)

CrewAI emits structured events for every tool call (tool name, arguments, agent role, timestamps, parent event IDs), but by default nothing records them durably. The opt-in output log file records only task start and end, and opt-in tracing, which does capture tool calls, buffers events in memory and uploads them to the CrewAI platform at the end of a run, so a crash loses the record. There is no attribution of who approved an action.

- **S L2:** Tracing captures structured tool-call events with args, agent role, timestamps and event correlation IDs. — [lib/crewai/src/crewai/events/types/tool_usage_events.py:15-18](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/events/types/tool_usage_events.py#L15-L18); [lib/crewai/src/crewai/events/base_events.py:82-84](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/events/base_events.py#L82-L84); [lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py:459-461](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py#L459-L461) (verified)
  - *To reach the next level:* No principal or approver attribution; L3 needs actor attribution separating agent, human and approver.
- **C L2:** Tool events are emitted from all executor paths, but hook blocks/approvals and memory writes are not part of an audit record. — [lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py:459-461](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py#L459-L461); [lib/crewai/src/crewai/utilities/agent_utils.py:1777](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/utilities/agent_utils.py#L1777) (verified)
  - *To reach the next level:* Approvals and denials not recorded; L3 needs them included.
- **D L0:** Tracing and the output log file are both off by default (consent/flag required). — [lib/crewai/src/crewai/crew.py:412-415](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/crew.py#L412-L415); [lib/crewai/src/crewai/crew.py:343-346](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/crew.py#L343-L346); [lib/crewai/src/crewai/events/listeners/tracing/utils.py:109-132](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/events/listeners/tracing/utils.py#L109-L132) (verified)
  - *To reach the next level:* Opt-in only; L1 needs recording on by default.
- **B L1:** Events are buffered in memory and sent at batch finalisation; a crash loses them. — [lib/crewai/src/crewai/events/listeners/tracing/trace_batch_manager.py:283-285](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/events/listeners/tracing/trace_batch_manager.py#L283-L285) (verified)
  - *To reach the next level:* Flushed late; L2 needs per-action flushing with surfaced errors.
- **Cap:** G1 — The only records that capture tool calls (tracing) are off by default and consent-gated.

### C10 Limits & kill switch — 0.25 (high)

Each agent stops after 25 reasoning iterations by default, which bounds a single loop. There is no default time limit, cost or token budget, or rate limit; the optional time limit raises an error but leaves the worker thread running to completion. Delegating to another agent starts a fresh iteration budget, and tasks are retried on error, so the effective ceiling multiplies, and there is no stop that interrupts in-flight tool calls.

- **S L1:** Only an iteration cap is enforced; the optional wall-clock timeout does not stop the running thread and there is no cost cap. — [lib/crewai/src/crewai/experimental/agent_executor.py:2245](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/experimental/agent_executor.py#L2245); [lib/crewai/src/crewai/agent/core.py:1045-1059](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agent/core.py#L1045-L1059); searched `rg -n -i 'max_cost|cost_limit|budget'` in `lib/crewai/src/crewai/agents lib/crewai/src/crewai/agent` → 0 hits (no cost or token budget in the agent loop) (verified)
  - *To reach the next level:* No enforced wall-clock or cost cap; L2 needs one of them enforced alongside the iteration cap.
- **C L1:** The cap applies per agent loop; delegated agents get their own fresh execute_task budget. — [lib/crewai/src/crewai/tools/agent_tools/base_agent_tools.py:120](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/tools/agent_tools/base_agent_tools.py#L120); [lib/crewai/src/crewai/agents/agent_builder/base_agent.py:286-288](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agents/agent_builder/base_agent.py#L286-L288) (verified)
  - *To reach the next level:* Delegation escapes the budget; L2 needs tool timeouts plus the top-level loop.
- **D L1:** max_iter=25 by default, but max_execution_time and max_rpm default to None, and delegation resets the iteration count. — [lib/crewai/src/crewai/agents/agent_builder/base_agent.py:286-288](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agents/agent_builder/base_agent.py#L286-L288); [lib/crewai/src/crewai/agent/core.py:258-261](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agent/core.py#L258-L261); [lib/crewai/src/crewai/agents/agent_builder/base_agent.py:275-276](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agents/agent_builder/base_agent.py#L275-L276) (verified)
  - *To reach the next level:* Time and rate limits unset by default; L2 needs sensible defaults across limits.
- **B L1:** Unlimited spend and time; a timed-out task keeps running in its thread. — [lib/crewai/src/crewai/agent/core.py:1045-1059](https://github.com/crewAIInc/crewAI/blob/738c8e19e35c2888d8e0663bc5cc45c5acf6ac2d/lib/crewai/src/crewai/agent/core.py#L1045-L1059); searched `rg -n -i 'max_cost|cost_limit|budget'` in `lib/crewai/src/crewai/agents lib/crewai/src/crewai/agent` → 0 hits (no cost or token budget in the agent loop) (verified)
  - *To reach the next level:* Ceilings are effectively unbounded; L2 needs moderate ceilings where stop ends the loop.
- **Cap:** none

## Rule-of-Two check
[A] untrusted input: Web search/scrape tools and MCP results enter context as ordinary messages (docs/edge/en/concepts/agent-capabilities.mdx:48-49) · [B] sensitive data/systems: Local files via FileReadTool and Google Sheets via platform apps (docs/edge/en/concepts/agent-capabilities.mdx:48-50) · [C] state change / egress: Gmail send via platform apps with no approval gate (docs/edge/en/concepts/agent-capabilities.mdx:50) · Same default session? Yes

## Highest-impact improvements
1. Load training data only from an explicitly configured path and in a safe format. — C7 S L0→L2, +0.150 before caps (Playbook 3)
2. Ship a default before_tool_call approval hook for tools flagged as side-effecting (email, writes, HTTP POST). — C2 D L0→L2, +0.100 before caps (Playbook 5)
3. Default max_execution_time and a token/cost budget that delegated agents share, and make the timeout cancel the worker. — C10 S L1→L2, +0.075 before caps (Playbook 3 step 3)
4. Write a local structured audit log of tool calls and hook decisions by default, outside the working directory. — C9 D L0→L2, +0.100 before caps (Playbook 1 step 3)
5. Replace import-time load_dotenv() with explicit config, and exclude .env and other auto-loaded files from file tools' default base directory. — C6 S L0→L2, +0.150 before caps (Playbook 2)

## Re-audit log
- No changes.

## Limitations
- Static source review of commit 738c8e1 only; nothing was executed, installed, or probed.
- Framework scored by its defaults: absent primitives score L0 even where a developer could add them; crewai-tools treated as the first-party tool package.
- Parts of the working-directory findings rely on library behaviour (including python-dotenv's find_dotenv search path), inferred and not executed.
- Not examined in depth: A2A server/client, Flow persistence and async feedback, CrewAI AMP/enterprise platform side, CLI (lib/cli), and most of the ~80 third-party integration tools beyond the security helpers.
- Model behaviour is out of scope; only code-level controls are scored.
- No reviewer-directed prompt injection found in the repo.
