Context
Guardrails (PR #534) is the platform's one AI-safety primitive: prompt injection, PII, content-safety, hallucination checks, block/warn/log policy. It only attaches via data lanes, so it can only ever check one place in a pipeline: whatever feeds the final response node. Every tool node (tool_http_request, tool_slack, tool_gmail, tool_github, tool_pipedrive, tool_gohighlevel, db_postgres/db_mysql-as-tool, tool_filesystem) runs entirely on the control plane, inside an agent's own turn — guardrails never sees it, in any pipeline, no matter how many tools an agent holds.
What
The ratio (actions guardrails can check) / (total actions an agent can take) shrinks with every tool node shipped — not because guardrails weakened, but because the denominator keeps growing. A 3-tool agent today has 1/4 of its actions checked; the same agent with 8 tools next year still has exactly 1/9 checked. The tool catalog is one of the fastest-growing parts of the product. Net effect: real safety coverage trends toward zero as the platform succeeds at adding integrations, with zero code change to guardrails required to cause that decline.
It's also a two-sided miss: guardrails' input-side checks exist to catch poisoned data before an agent acts on it. Since tool calls happen inside the agent's own turn, a poisoned webhook payload or scraped doc can drive a tool call with no check on either the tainted input or the resulting action — the standard indirect-prompt-injection-into-tool-use gap.
Where it lives
nodes/src/nodes/guardrails/ — lanes only (answers, documents, questions)
- Every
tool_* / db_*-as-tool node — lanes: {}, invoked only via control
agent_crewai_subagent — lanes: {} even for its own output, so nothing downstream can gate it either
Repro / trace
Try to build: crewai_subagent (writes content) → guardrails → tool_slack (send). No lane connection is possible between a subagent's tool call and a guardrails node — guardrails can only ever gate what's already been returned to a lane-connected component.
Suggested fix
Let guardrails attach via control directly to a tool node (classType: "guard", from: <tool_id>), running the same policy checks on the agent's tool-call args (pre) and result (post). One guardrails node, reusable across every tool an agent holds — same config surface as today, no per-tool variant needed. guardrails becomes attachable via control in addition to input.
Severity / impact
High and compounding: coverage degrades automatically with every future tool node. One fix (control-plane attachment) closes the gap for the current catalog and everything added after.
Context
Guardrails (PR #534) is the platform's one AI-safety primitive: prompt injection, PII, content-safety, hallucination checks,
block/warn/logpolicy. It only attaches via data lanes, so it can only ever check one place in a pipeline: whatever feeds the final response node. Every tool node (tool_http_request,tool_slack,tool_gmail,tool_github,tool_pipedrive,tool_gohighlevel,db_postgres/db_mysql-as-tool,tool_filesystem) runs entirely on the control plane, inside an agent's own turn — guardrails never sees it, in any pipeline, no matter how many tools an agent holds.What
The ratio (actions guardrails can check) / (total actions an agent can take) shrinks with every tool node shipped — not because guardrails weakened, but because the denominator keeps growing. A 3-tool agent today has 1/4 of its actions checked; the same agent with 8 tools next year still has exactly 1/9 checked. The tool catalog is one of the fastest-growing parts of the product. Net effect: real safety coverage trends toward zero as the platform succeeds at adding integrations, with zero code change to guardrails required to cause that decline.
It's also a two-sided miss: guardrails' input-side checks exist to catch poisoned data before an agent acts on it. Since tool calls happen inside the agent's own turn, a poisoned webhook payload or scraped doc can drive a tool call with no check on either the tainted input or the resulting action — the standard indirect-prompt-injection-into-tool-use gap.
Where it lives
nodes/src/nodes/guardrails/— lanes only (answers,documents,questions)tool_*/db_*-as-tool node —lanes: {}, invoked only viacontrolagent_crewai_subagent—lanes: {}even for its own output, so nothing downstream can gate it eitherRepro / trace
Try to build:
crewai_subagent (writes content) → guardrails → tool_slack (send). No lane connection is possible between a subagent's tool call and a guardrails node — guardrails can only ever gate what's already been returned to a lane-connected component.Suggested fix
Let
guardrailsattach viacontroldirectly to a tool node (classType: "guard",from: <tool_id>), running the same policy checks on the agent's tool-call args (pre) and result (post). One guardrails node, reusable across every tool an agent holds — same config surface as today, no per-tool variant needed.guardrailsbecomes attachable viacontrolin addition toinput.Severity / impact
High and compounding: coverage degrades automatically with every future tool node. One fix (control-plane attachment) closes the gap for the current catalog and everything added after.