# Defense-in-Depth Score: n8n

**Repo:** https://github.com/n8n-io/n8n · **Commit:** `ea9f451076722a6784e0f9d78af4410952be9a99` · **Reviewed:** 2026-10-03
**What it is:** Workflow automation with AI agents
**Category:** Agent Frameworks
**Scored configuration:** Self-hosted n8n 2.42.0 (Docker image defaults): an AI Agent node (Tools Agent v3.1) in a workflow whose triggers, tools, credentials and memory are wired by the author, task runners in default internal mode, with no HITL review nodes, Guardrails, SSRF protection or external runners enabled.
**Agent surface (default):** code execution yes · filesystem write yes · network egress yes · external credentials yes · persistent memory yes · untrusted input yes · third party extensions yes · sub agents yes · external communication yes

## Score: 3.4 / 10.0 (Minimal)

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


As shipped, an n8n AI agent runs every tool call it decides on without human review, using the workflow author's long-lived, broadly scoped credentials. If someone gets instructions into what the agent reads (an email, a chat message, a web page), it can leak data and send, post or write on their behalf. n8n has good opt-in controls, including per-tool human approval that shows the exact call, SSRF protection and an isolated runner container, but none are on by default. Code tasks run as the same OS user that holds the credential encryption key.

## Critical gaps
- Agent tools run with long-lived, account-wide OAuth grants by default (full Gmail mailbox scope), so a hijacked agent controls the connected accounts. (ASI03, T3; C1) — [packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:3-10](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts#L3-L10); [packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts:23-26](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts#L23-L26)
- Default internal task runner runs Code node/Code tool code as the same OS user as n8n using node:vm; an escape can read the instance encryption key and decrypt every stored credential. (ASI05, T11; C4) — [packages/@n8n/config/src/configs/runners.config.ts:17](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/runners.config.ts#L17); [packages/@n8n/task-runner/src/js-task-runner/js-task-runner.ts:23](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/task-runner/src/js-task-runner/js-task-runner.ts#L23); [packages/core/src/instance-settings/instance-settings.ts:60](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/instance-settings/instance-settings.ts#L60); [packages/core/src/instance-settings/instance-settings.ts:442](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/instance-settings/instance-settings.ts#L442)
- Untrusted content (email/chat/webhook input and tool results) reaches an agent that holds broad credentials and send/HTTP tools with no approval, so a prompt injection can leak data and take irreversible actions unattended. (ASI01, T6, LLM01; C5) — [packages/@n8n/nodes-langchain/utils/agent-execution/buildSteps.ts:401](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/buildSteps.ts#L401); [packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:229-272](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts#L229-L272); [packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:3-10](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts#L3-L10)
- Community node packages, unverified ones allowed by default, load into the n8n main process with access to every stored credential. (ASI04, T17; C7) — [packages/cli/src/modules/community-packages/community-packages.service.ts:578](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.service.ts#L578); [packages/cli/src/modules/community-packages/community-packages.config.ts:12-25](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.config.ts#L12-L25)

## Criterion details

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

An n8n agent acts with whatever stored credentials the workflow author attaches to each tool node, and n8n's built-in OAuth credentials request very broad scopes by default (full Gmail mailbox access, Slack scopes that include profile and user-group writes). Before a run, n8n checks that the workflow's project is allowed to use every credential it references, so a workflow cannot borrow another project's credentials. Nothing narrows authority per request or per end user: everyone who chats with or triggers an agent acts with the author's credentials. A hijacked agent therefore holds full-account access to every connected service.

- **S L1:** Each tool node uses a dedicated stored credential, but the shipped OAuth credential types request maximal scopes (e.g. https://mail.google.com/ for Gmail; users.profile:write and usergroups:write for Slack). — [packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:3-10](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts#L3-L10); [packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts:23-26](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts#L23-L26) (verified)
  - *To reach the next level:* Built-in credential types do not request minimal or read-only scopes, so read tools and write tools share one broad grant.
- **C L2:** A pre-execution permission check verifies that every credential referenced by any node in the workflow, including tool sub-nodes, is usable by the workflow's project. — [packages/cli/src/workflow-runner.ts:420](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/workflow-runner.ts#L420); [packages/cli/src/executions/pre-execution-checks/credentials-permission-checker.ts:74](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/executions/pre-execution-checks/credentials-permission-checker.ts#L74) (verified)
  - *To reach the next level:* Authorization is checked per workflow/project, not per action against the requesting principal; chat and webhook requesters inherit the author's credentials.
- **D L0:** Default installs give credentials the maximal scope defined in each credential type; narrowing requires the operator to edit scopes or use read-only service accounts manually. — [packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:3-10](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts#L3-L10) (verified)
  - *To reach the next level:* No near-minimal default role; least privilege is manual hardening.
- **B L0:** A hijacked agent can use full-account credentials (entire Gmail mailbox, broad Slack workspace scopes, any database user the author attached) across every connected production service. — [packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:3-10](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts#L3-L10); [packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts:23-26](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts#L23-L26) (verified)
  - *To reach the next level:* Credentials are long-lived account-wide grants rather than scoped, short-lived tokens.
- **Cap:** none
- **Notes:** D is L0 because the shipped credential types default to maximal scopes, not because a control is opt-in; G1 does not apply.

### C2 Approval gates — 0.30 (high)

By default the AI Agent node executes every tool call the model makes with no human approval: tool calls are routed straight to the tool node. n8n ships a solid opt-in Human-in-the-Loop layer: an author can place a Slack, email, Telegram or chat 'Human review' node in front of chosen tools, and the approver is shown the exact tool name and parameters, the approved arguments are exactly what runs, and rejection is fed back to the agent. But it only covers the tools the author remembers to wire through it, and the actions it protects (sending email, posting messages, writing to databases, arbitrary HTTP calls) are mostly irreversible.

- **default configuration** (default; raw 0.00 → 0.00)
  - **S L0:** The Tools Agent dispatches each model tool call directly to its node; no approval condition exists unless an HITL node was wired in. — [packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:229-272](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts#L229-L272); searched `rg -n -i approv` in `packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/V3` → 5 hits (All 5 hits are the opt-in HITL path (executeBatch.ts:58,61; resolveSubAgentRequest.ts:56) or its tests (2 hits); no default approval condition exists in the agent loop.) (verified)
    - *To reach the next level:* No approval step in the default agent loop.
  - **C L0:** Every tool, including HTTP Request and Code tools, executes ungated in the default configuration. — [packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:229-272](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts#L229-L272) (verified)
    - *To reach the next level:* No tool path traverses a gate by default.
  - **D L0:** Approval is opt-in: it only exists for tools the author connects through a *HitlTool node. — [packages/workflow/src/node-helpers.ts:2014](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/workflow/src/node-helpers.ts#L2014); [packages/core/src/execution-engine/node-execution-context/utils/get-input-connection-data.ts:64-100](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/execution-engine/node-execution-context/utils/get-input-connection-data.ts#L64-L100) (verified)
    - *To reach the next level:* Approval is not on by default for any tool.
  - **B L0:** Typical agent tools (Gmail send, Slack post, database write, HTTP Request) perform irreversible external actions with no undo or preview. — [packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:3-10](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts#L3-L10); [packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:229-272](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts#L229-L272) (verified)
    - *To reach the next level:* No checkpoints, previews, or spend/recipient bounds on consequential tool actions.
- **opt-in Human-in-the-Loop tool review nodes** (alt; raw 0.30, cap G1 → 0.30) ← counted
  - **S L3:** Per-call approval via signed sendAndWait link; the default message shows the exact tool name and parameters, approved calls execute the stored original input, and denial is returned to the agent. — [packages/cli/src/tool-generation/hitl-tools.ts:88-96](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/tool-generation/hitl-tools.ts#L88-L96); [packages/@n8n/nodes-langchain/utils/agent-execution/processHitlResponses.ts:133-139](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/processHitlResponses.ts#L133-L139); [packages/cli/src/webhooks/waiting-webhooks.ts:211-224](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/webhooks/waiting-webhooks.ts#L211-L224) (verified)
    - *To reach the next level:* No argument-level allow/deny/escalate policy; the author can replace the message template with a model-filled one.
  - **C L1:** Only tools explicitly wired through an HITL node are gated; all other connected tools still run directly (HITL inside a sub-agent aborts rather than bypasses). — [packages/core/src/execution-engine/node-execution-context/utils/get-input-connection-data.ts:64-100](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/execution-engine/node-execution-context/utils/get-input-connection-data.ts#L64-L100); [packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/resolveSubAgentRequest.ts:56](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/resolveSubAgentRequest.ts#L56) (verified)
    - *To reach the next level:* Gating is per-tool opt-in, so ungated mutating tools coexist with gated ones.
  - **D L0:** HITL review exists only when an author adds a *HitlTool node to the workflow. — [packages/workflow/src/node-helpers.ts:2014](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/workflow/src/node-helpers.ts#L2014) (verified)
    - *To reach the next level:* Not on by default.
  - **B L0:** Wrongly approved or ungated actions remain irreversible external side effects with no rollback. — [packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:229-272](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts#L229-L272) (verified)
    - *To reach the next level:* No rollback, previews, or rate/quantity limits on consequential actions.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.
- **Notes:** Unknown tool names returned by the model are dropped rather than executed (createEngineRequests.ts:234).

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

n8n narrows tools well in one respect: an author turns a regular node into a tool and chooses which parameters the model may fill (via $fromAI placeholders, which get typed schemas), so a Gmail tool can have a fixed recipient. File nodes are confined to ~/.n8n-files with real-path and symlink checks, and Execute Command is excluded by default. But generic tools stay generic: the HTTP Request tool can be given a model-chosen URL, SSRF protection is off by default, database tools accept raw model-written SQL, and the MCP client tool exposes every server tool by default. Misused tools act directly on production systems.

- **S L2:** Model-filled parameters get typed zod schemas and file paths are realpath/symlink-checked, but URL and SQL arguments pass through unvalidated unless SSRF protection is turned on. — [packages/workflow/src/from-ai-parse-utils.ts:27-38](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/workflow/src/from-ai-parse-utils.ts#L27-L38); [packages/core/src/execution-engine/node-execution-context/utils/file-system-helper-functions.ts:60-104](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/execution-engine/node-execution-context/utils/file-system-helper-functions.ts#L60-L104); [packages/@n8n/config/src/configs/ssrf-protection.config.ts:91-92](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/ssrf-protection.config.ts#L91-L92) (verified)
  - *To reach the next level:* No host allowlist or internal-address blocking by default and no parameterization enforced for model-written SQL.
- **C L2:** Typed $fromAI schemas apply to every node used as a tool and the file-path guard applies to the file nodes; HTTP/SQL tools are not validated by default. — [packages/workflow/src/from-ai-parse-utils.ts:27-38](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/workflow/src/from-ai-parse-utils.ts#L27-L38); [packages/@n8n/config/src/configs/security.config.ts:47-57](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/security.config.ts#L47-L57) (verified)
  - *To reach the next level:* No shared validation layer that every tool, including community nodes and MCP tools, inherits.
- **D L2:** The agent only receives tools the author connects and the model cannot add tools; Execute Command is excluded by default, but connected toolkits such as the MCP client expose all server tools by default. — [packages/@n8n/config/src/configs/nodes.config.ts:38-39](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/nodes.config.ts#L38-L39); [packages/@n8n/nodes-langchain/nodes/mcp/McpClientTool/McpClientTool.node.ts:201-206](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/mcp/McpClientTool/McpClientTool.node.ts#L201-L206) (verified)
  - *To reach the next level:* Write and egress tools are not off by default within connected toolkits (MCP include defaults to 'all'), and SSRF protection is off.
- **B L1:** Misused tools reach production services and arbitrary hosts; limits are only what the author fixed in node parameters. — [packages/@n8n/config/src/configs/ssrf-protection.config.ts:91-92](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/ssrf-protection.config.ts#L91-L92); [packages/workflow/src/credential-domain-restrictions.ts:14-37](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/workflow/src/credential-domain-restrictions.ts#L14-L37) (verified)
  - *To reach the next level:* No quantity bounds (max recipients/rows/amount) on tool actions.
- **Cap:** none

### C4 Code-execution isolation — 0.33 (high)

Code written in Code nodes and the Code tool (the agent passes it inputs) runs in n8n's task runner. By default the runner is a child process of n8n, with a scrubbed environment, Node's vm module, frozen globals and code-generation-from-strings disabled. Node's vm module is not a security boundary, and the child runs as the same OS user as n8n, so an escape can read ~/.n8n/config (the credential encryption key) and the database, which means every stored credential. A hidden legacy LangChain Code node still runs code in-process through vm2. A separate runner container is available but opt-in.

- **default configuration** (default; raw 0.25 → 0.25)
  - **S L1:** Internal-mode runner: same-user child process using node:vm with hardening flags; node:vm is not a security boundary. — [packages/@n8n/config/src/configs/runners.config.ts:17](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/runners.config.ts#L17); [packages/@n8n/task-runner/src/js-task-runner/js-task-runner.ts:23](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/task-runner/src/js-task-runner/js-task-runner.ts#L23); [packages/cli/src/task-runners/task-runner-process-js.ts:34-42](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/task-runners/task-runner-process-js.ts#L34-L42) (verified)
    - *To reach the next level:* No OS-level separation (different user, container, or namespace) in the default mode.
  - **C L1:** Code node and Code tool go through the runner, but the LangChain Code node runs user code in-process in the n8n main process via vm2. — [packages/@n8n/nodes-langchain/nodes/code/Code.node.ts:220](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/code/Code.node.ts#L220); [packages/nodes-base/nodes/Code/JavaScriptSandbox.ts:45](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/nodes/Code/JavaScriptSandbox.ts#L45); [packages/@n8n/nodes-langchain/nodes/code/Code.node.ts:239-246](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/code/Code.node.ts#L239-L246) (verified)
    - *To reach the next level:* Not every execution path uses the runner; the vm2 in-process path remains loadable.
  - **D L2:** Runner hardening is on by default; an operator env var (N8N_RUNNERS_INSECURE_MODE) disables it. — [packages/@n8n/config/src/configs/runners.config.ts:88-90](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/runners.config.ts#L88-L90); [packages/cli/src/task-runners/task-runner-process-js.ts:34-42](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/task-runners/task-runner-process-js.ts#L34-L42) (verified)
    - *To reach the next level:* Disabling hardening is a plain env var; no per-call approval or stronger policy separation.
  - **B L0:** An escape lands as the n8n OS user with read access to ~/.n8n/config (encryption key, mode 0600 but same uid) and the credential database, plus unrestricted network. — [packages/core/src/instance-settings/instance-settings.ts:60](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/instance-settings/instance-settings.ts#L60); [packages/core/src/instance-settings/instance-settings.ts:355](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/instance-settings/instance-settings.ts#L355); [packages/core/src/instance-settings/instance-settings.ts:442](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/instance-settings/instance-settings.ts#L442); [packages/cli/src/task-runners/task-runner-process-js.ts:53-85](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/task-runners/task-runner-process-js.ts#L53-L85) (verified)
    - *To reach the next level:* Sandbox can reach the instance's secrets and network; no workspace-only, no-secret, egress-restricted boundary.
- **opt-in external task runner container (n8nio/runners)** (alt; raw 0.33, cap G1 → 0.33) ← counted
  - **S L2:** Separate stock container running as non-root user 'runner' with an env allowlist; no seccomp/read-only/cap-drop defined in the repo. — [docker/images/runners/Dockerfile:156](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/docker/images/runners/Dockerfile#L156) (verified)
    - *To reach the next level:* No hardened profile (dropped capabilities, seccomp, read-only rootfs, network deny) shipped.
  - **C L1:** Code and Code tool tasks go to the external container, but the LangChain Code node still runs vm2 in the n8n process. — [packages/@n8n/nodes-langchain/nodes/code/Code.node.ts:220](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/code/Code.node.ts#L220) (verified)
    - *To reach the next level:* In-process vm2 path is not routed to the container.
  - **D L0:** External mode must be selected with N8N_RUNNERS_MODE=external; default is internal. — [packages/@n8n/config/src/configs/runners.config.ts:17](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/runners.config.ts#L17) (verified)
    - *To reach the next level:* Off by default.
  - **B L2:** Escape lands in a container without n8n's data directory or secrets, but with unrestricted network. — [docker/images/runners/Dockerfile:156](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/docker/images/runners/Dockerfile#L156) (verified)
    - *To reach the next level:* No egress restriction or ephemeral per-task sandbox.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.

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

Agents commonly read attacker-reachable content (webhook and chat input, inbound email triggers, web pages and API responses returned by tools), and those tool results go into the model's context with no marking or provenance. Nothing in the agent loop limits what a hijacked agent can do after reading untrusted content. The opt-in Guardrails node can screen text for jailbreaks or PII, but it is a detector the author has to place by hand. In the common setup (email or chat in, credentials to mail and other services, HTTP or send tools out) a successful injection can leak data and take irreversible actions with no human involved.

- **default configuration** (default; raw 0.00, cap C5-WORSTCASE → 0.00)
  - **S L0:** No structural limit: tool observations are appended to the conversation as ordinary tool results. — [packages/@n8n/nodes-langchain/utils/agent-execution/buildSteps.ts:401](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/buildSteps.ts#L401); searched `rg -n -i -e untrusted -e prompt.injection -e taint` in `packages/@n8n/nodes-langchain/nodes/agents packages/@n8n/nodes-langchain/utils/agent-execution` → 0 hits (No provenance, taint or untrusted-content handling anywhere in the agent loop or tool-result plumbing.) (verified)
    - *To reach the next level:* No detection, approval-after-untrusted-input, or quarantine in the default agent loop.
  - **C L0:** Untrusted sources (triggers, tool results, MCP tool descriptions) are not distinguished. — [packages/@n8n/nodes-langchain/utils/agent-execution/buildSteps.ts:401](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/buildSteps.ts#L401); [packages/@n8n/nodes-langchain/nodes/mcp/McpClientTool/McpClientTool.node.ts:201-206](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/mcp/McpClientTool/McpClientTool.node.ts#L201-L206) (verified)
    - *To reach the next level:* No source is handled as untrusted.
  - **D L0:** No control is on by default. — searched `rg -n -i -e untrusted -e prompt.injection -e taint` in `packages/@n8n/nodes-langchain/nodes/agents packages/@n8n/nodes-langchain/utils/agent-execution` → 0 hits (No provenance, taint or untrusted-content handling anywhere in the agent loop or tool-result plumbing.) (verified)
    - *To reach the next level:* Nothing enabled by default.
  - **B L0:** A hijacked agent holding broad credentials and an HTTP or send tool can exfiltrate data and take irreversible actions unattended; one workflow serves every chat/webhook requester. — [packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:3-10](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts#L3-L10); [packages/workflow/src/credential-domain-restrictions.ts:14-37](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/workflow/src/credential-domain-restrictions.ts#L14-L37); [packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:229-272](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts#L229-L272) (verified)
    - *To reach the next level:* Sessions combine untrusted input, sensitive credentials and egress with no human involved.
- **opt-in Guardrails node (jailbreak/PII/keyword detection)** (alt; raw 0.15, cap G1 → 0.15) ← counted
  - **S L1:** Classifier/regex detection of jailbreaks, PII and secrets on text the author routes through the node. — [packages/@n8n/nodes-langchain/nodes/Guardrails/description.ts:112-115](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/Guardrails/description.ts#L112-L115) (verified)
    - *To reach the next level:* Detection only; no structural Rule-of-Two enforcement.
  - **C L1:** Only covers the text explicitly routed through the node, typically the user message; tool results inside the agent loop are not screened. — [packages/@n8n/nodes-langchain/nodes/Guardrails/description.ts:112-115](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/Guardrails/description.ts#L112-L115); [packages/@n8n/nodes-langchain/utils/agent-execution/buildSteps.ts:401](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/buildSteps.ts#L401) (verified)
    - *To reach the next level:* Tool results, MCP descriptions and sub-agent messages bypass it.
  - **D L0:** Guardrails exist only if the author adds the node. — [packages/@n8n/nodes-langchain/nodes/Guardrails/description.ts:112-115](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/Guardrails/description.ts#L112-L115) (verified)
    - *To reach the next level:* Off by default.
  - **B L0:** Even with Guardrails, a missed injection retains leak plus irreversible-action capability unattended. — [packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:229-272](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts#L229-L272); [packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:3-10](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts#L3-L10) (verified)
    - *To reach the next level:* No egress or state-change restriction once untrusted content is read.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.

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

Conversation memory (Simple, Postgres, Redis, MongoDB, Zep and others) stores past turns, including what the agent said after reading injected content, and replays them as chat history in later turns, where they can steer tool use. Reads and writes are recorded in execution data, but nothing validates, tags or expires what is stored. Sessions are separated by a session ID that, for chat triggers, comes from the request body rather than from an authenticated user. There are no auto-loaded repo instruction files, which removes a common poisoning path.

- **S L1:** Memory writes are logged via logWrapper but not validated, and history is replayed as trusted conversation context. — searched `rg -n 'response: logWrapper\(memory'` in `packages/@n8n/nodes-langchain/nodes/memory` → 7 hits (Every chat-memory sub-node is wrapped in logWrapper, which records reads/writes in execution data; nothing validates or gates what is written.) (verified)
  - *To reach the next level:* No provenance tagging or gating of memory writes; no expiry.
- **C L1:** Logging covers all chat-memory nodes; vector-store insert tools and memory content are not validated anywhere. — searched `rg -n 'response: logWrapper\(memory'` in `packages/@n8n/nodes-langchain/nodes/memory` → 7 hits (Every chat-memory sub-node is wrapped in logWrapper, which records reads/writes in execution data; nothing validates or gates what is written.) (verified)
  - *To reach the next level:* No control on the main memory store beyond logging.
- **D L1:** Per-session keys are enforced in the memory lookup, but the session ID is taken from the client request body, not bound to an authenticated principal. — [packages/@n8n/nodes-langchain/utils/helpers.ts:124-131](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/helpers.ts#L124-L131); [packages/@n8n/nodes-langchain/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.ts:177](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.ts#L177) (verified)
  - *To reach the next level:* Isolation is not bound to an authenticated user.
- **B L1:** Poisoned history persists for the session (indefinitely in external stores) and can trigger tool use in later turns. — [packages/@n8n/nodes-langchain/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.ts:177](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.ts#L177) (verified)
  - *To reach the next level:* Poisoned memory can still drive ungated tool use.
- **Cap:** none

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

Community nodes are third-party npm packages an instance owner or admin can install from the UI, and the feature is on by default. Installs skip npm lifecycle scripts, resolve to an exact version that is recorded, and n8n-vetted packages are checked against a known checksum. Unverified packages are allowed by default with no integrity check, and installed nodes load into the main n8n process, where they can reach every credential the instance holds. MCP client tools connect only to remote servers, so no third-party code runs locally that way.

- **S L2:** Installed versions are pinned (exact version persisted); checksum verification applies only to vetted packages; unverified packages install from 'latest' by default. — [packages/cli/src/modules/community-packages/community-packages.service.ts:541](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.service.ts#L541); [packages/cli/src/modules/community-packages/community-packages.service.ts:524-525](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.service.ts#L524-L525); [packages/cli/src/modules/community-packages/community-packages.service.ts:506-510](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.service.ts#L506-L510) (verified)
  - *To reach the next level:* No integrity check or curated-registry requirement for unverified packages.
- **C L2:** Community npm packages are the only local third-party code type, and the vetting path covers part of them; MCP is remote-only. — [packages/cli/src/modules/community-packages/community-packages.service.ts:524-525](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.service.ts#L524-L525); [packages/cli/src/modules/community-packages/community-packages.service.ts:1039](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.service.ts#L1039) (verified)
  - *To reach the next level:* Unverified community packages are not integrity-checked.
- **D L2:** Installation requires an explicit owner/admin action, but unverified packages are allowed and nothing shows what code or permissions a node will have. — [packages/cli/src/modules/community-packages/community-packages.controller.ts:13-14](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.controller.ts#L13-L14); [packages/cli/src/modules/community-packages/community-packages.config.ts:12-25](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.config.ts#L12-L25) (verified)
  - *To reach the next level:* No display of the code/permissions an extension receives; unverified installs enabled by default.
- **B L0:** Community nodes are loaded into the n8n main process and run with access to all decrypted credentials and the database. — [packages/cli/src/modules/community-packages/community-packages.service.ts:578](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/community-packages/community-packages.service.ts#L578) (verified)
  - *To reach the next level:* No per-extension process, sandbox, or scoped credentials.
- **Cap:** none

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

Credentials are encrypted at rest in n8n's database and injected by node code at execution time, so the model never sees them, and the task runner gets a scrubbed environment. The encryption key sits next to the data in ~/.n8n/config, readable by the n8n user. Execution records store full prompts, tool inputs and outputs unredacted by default, and anonymous telemetry is on by default (content-free on self-hosted). Credentials are long-lived and broad, and by default may be sent to any domain from the HTTP Request tool.

- **S L2:** AES-encrypted credential store with a locally generated key file (mode 0600); credentials never enter model context by design, but execution-data redaction is off. — [packages/core/src/instance-settings/instance-settings.ts:355](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/instance-settings/instance-settings.ts#L355); [packages/core/src/instance-settings/instance-settings.ts:442](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/core/src/instance-settings/instance-settings.ts#L442); [packages/cli/src/modules/redaction/redaction-context-hook.ts:60](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/redaction/redaction-context-hook.ts#L60) (verified)
  - *To reach the next level:* Key is not in an OS keychain/secret manager by default and execution data is not redacted.
- **C L2:** Model-bound messages and runner subprocess environments are protected; execution data (transcripts) is stored unredacted by default. — [packages/cli/src/task-runners/task-runner-process-js.ts:53-85](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/task-runners/task-runner-process-js.ts#L53-L85); [packages/cli/src/modules/redaction/redaction-context-hook.ts:60](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/redaction/redaction-context-hook.ts#L60) (verified)
  - *To reach the next level:* Transcripts/execution data and logs are not redacted on the default path.
- **D L1:** Telemetry is on by default (prompts only sent on cloud), and full execution data is saved by default with redaction policy 'none'. — [packages/@n8n/config/src/configs/diagnostics.config.ts:17-18](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/diagnostics.config.ts#L17-L18); [packages/workflow/src/telemetry-helpers.ts:675](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/workflow/src/telemetry-helpers.ts#L675); [packages/@n8n/config/src/configs/executions.config.ts:148-149](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/executions.config.ts#L148-L149); [packages/cli/src/modules/redaction/redaction-context-hook.ts:60](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/cli/src/modules/redaction/redaction-context-hook.ts#L60) (verified)
  - *To reach the next level:* Telemetry is not opt-in and redaction is not on by default.
- **B L1:** Stored keys are long-lived, broadly scoped OAuth/API credentials; not visible to the model, but a credential may be sent to any domain by default. — [packages/workflow/src/credential-domain-restrictions.ts:14-37](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/workflow/src/credential-domain-restrictions.ts#L14-L37); [packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:3-10](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts#L3-L10) (verified)
  - *To reach the next level:* Credentials are not scoped or short-lived.
- **Cap:** none

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

Every execution is saved by default with each node run, including each agent tool call, its inputs and outputs, timestamps, and HITL approvals or denials, in n8n's database, and an event log is written by default. That gives a structured, replayable trajectory. Records don't identify the requesting end user, aren't tamper-evident, can be switched off per workflow, and are written when the execution finishes rather than as each step happens, so a crash can lose them.

- **S L2:** Structured per-node run data (tool inputs/outputs, timestamps) saved for every execution. — [packages/@n8n/config/src/configs/executions.config.ts:148-149](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/executions.config.ts#L148-L149); [packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:229-272](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts#L229-L272) (verified)
  - *To reach the next level:* No actor attribution of the requesting principal and no correlation beyond execution IDs.
- **C L3:** Every tool call is executed as a node run by the engine, including community and MCP tools, sub-agent tools and HITL approval nodes, so all are recorded. — [packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:229-272](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts#L229-L272); [packages/@n8n/nodes-langchain/utils/agent-execution/processHitlResponses.ts:133-139](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/utils/agent-execution/processHitlResponses.ts#L133-L139); [packages/@n8n/config/src/configs/event-bus.config.ts:16-17](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/event-bus.config.ts#L16-L17) (verified)
  - *To reach the next level:* Configuration changes, memory writes and credential use are not all in one audit record by default.
- **D L2:** On by default and stored in the n8n database outside any agent tool's reach, but per-workflow settings or env vars can turn saving off silently. — [packages/@n8n/config/src/configs/executions.config.ts:148-149](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/executions.config.ts#L148-L149) (verified)
  - *To reach the next level:* Not written by a component isolated from the n8n process; disabling isn't itself logged.
- **B L1:** Execution progress isn't saved per step by default; data is persisted at the end of the execution. — [packages/@n8n/config/src/configs/executions.config.ts:152-153](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/executions.config.ts#L152-L153) (verified)
  - *To reach the next level:* Records are not flushed per action, so a crash loses the trajectory.
- **Cap:** none

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

The AI Agent node stops after 10 tool iterations by default, and stopping an execution signals the agent to cancel. Code tasks time out after 5 minutes. There is no token or cost cap, the overall execution timeout is unlimited by default, production concurrency is unlimited, and sub-agents get their own fresh iteration budget. Triggers can start a workflow again and again with no rate limit.

- **S L2:** Iteration cap enforced in code plus an execution timeout (when set) and runner task timeout; cancel signal is passed into the agent. — [packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/checkMaxIterations.ts:37-41](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/checkMaxIterations.ts#L37-L41); [packages/@n8n/config/src/configs/executions.config.ts:93-103](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/executions.config.ts#L93-L103); [packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/runAgent.ts:90](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/runAgent.ts#L90) (verified)
  - *To reach the next level:* No token/cost cap and no rate limits on side-effecting tools.
- **C L2:** The cap applies to the top-level agent loop and code tasks have a timeout, but sub-agents run their own executor with a fresh iteration budget. — [packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/executeBatch.ts:75-81](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/executeBatch.ts#L75-L81); [packages/@n8n/config/src/configs/runners.config.ts:55](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/runners.config.ts#L55); [packages/@n8n/nodes-langchain/nodes/agents/Agent/V3/AgentToolV3.node.ts:101-105](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/agents/Agent/V3/AgentToolV3.node.ts#L101-L105) (verified)
  - *To reach the next level:* Sub-agents and repeated triggers do not count against a shared budget.
- **D L1:** maxIterations defaults to 10, but the execution timeout is -1 (unlimited) and production concurrency is unlimited by default. — [packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/options.ts:21-25](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/options.ts#L21-L25); [packages/@n8n/config/src/configs/executions.config.ts:93-103](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/executions.config.ts#L93-L103); [packages/@n8n/config/src/configs/executions.config.ts:25-26](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/executions.config.ts#L25-L26) (verified)
  - *To reach the next level:* Wall-clock and concurrency limits are not set by default.
- **B L1:** With no default wall-clock or spend ceiling, a runaway workflow (or repeatedly triggered agent) can keep acting and spending. — [packages/@n8n/config/src/configs/executions.config.ts:93-103](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/executions.config.ts#L93-L103); [packages/@n8n/config/src/configs/executions.config.ts:25-26](https://github.com/n8n-io/n8n/blob/ea9f451076722a6784e0f9d78af4410952be9a99/packages/@n8n/config/src/configs/executions.config.ts#L25-L26) (verified)
  - *To reach the next level:* No tight default time/cost ceiling.
- **Cap:** none

## Rule-of-Two check
[A] untrusted input: Webhook/chat/email triggers and tool results enter context unmarked (packages/@n8n/nodes-langchain/utils/agent-execution/buildSteps.ts:401) · [B] sensitive data/systems: Stored OAuth credentials with full-account scopes, e.g. Gmail https://mail.google.com/ (packages/nodes-base/credentials/GmailOAuth2Api.credentials.ts:7) · [C] state change / egress: Tool calls dispatched without approval (packages/@n8n/nodes-langchain/utils/agent-execution/createEngineRequests.ts:259); SSRF guard off (packages/@n8n/config/src/configs/ssrf-protection.config.ts:92) · Same default session? Yes

## Highest-impact improvements
1. Run task runners as a separate OS user/container by default (external mode) so a sandbox escape cannot read ~/.n8n/config or the credential database. — C4 B L0→L2, +0.100 before caps (Playbook 3)
2. Enable N8N_SSRF_PROTECTION_ENABLED by default and default credential 'Allowed HTTP Request Domains' to the credential's own service. — C3 S L2→L3, +0.075 before caps (Playbook 3)
3. Set a finite default EXECUTIONS_TIMEOUT and production concurrency limit. — C10 D L1→L2, +0.050 before caps (Playbook 3)
4. Require HITL review by default for write/egress-capable tool nodes connected to an agent, with an explicit operator opt-out. — C2 D L0→L3, +0.150 before caps (Playbook 5)
5. Mark tool results as untrusted and force approval on send/HTTP tools once untrusted content is in the session. — C5 S L0→L2, +0.150 before caps (Playbook 1)

## Re-audit log
- No changes.

## Limitations
- Static source review of the pinned commit only; nothing was built, installed or run.
- Scope is the AI Agent node (Tools Agent V3) in workflows. The default-loaded Instance AI assistant (packages/@n8n/instance-ai, packages/cli/src/modules/instance-ai) and the standalone Agents module (packages/cli/src/modules/agents), which have their own approval, budget-guardrail and sandbox code, were not scored and may differ.
- Pinned commit is 267 commits after tag n8n@2.42.0; version left null.
- Default-loaded but not deeply examined: dynamic/runtime-credentials, external-secrets, log-streaming and OTel modules (several are license-gated), and individual credential types beyond Gmail/Slack.
- Cloud (n8n.cloud) deployments differ (e.g. telemetry includes prompts on cloud, telemetry-helpers.ts:675); only self-hosted defaults were scored.
- No reviewer-steering text aimed at AI auditors was observed in the files read (AGENTS.md/CLAUDE.md are contributor guidance).
