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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions lib/crewai/src/crewai/agent/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1216,16 +1216,32 @@ def _inject_date_to_task(self, task: Task) -> None:
self._logger.log("warning", f"Failed to inject date: {e!s}")

def _validate_docker_installation(self) -> None:
"""Check if Docker is installed and running."""
"""Check if Docker is installed and running.

Validates the subprocess command against the agent's governance
policy before execution (OWASP ASI08: Uncontrolled Code Execution).
"""
from crewai.security.governance import GovernanceError

docker_path = shutil.which("docker")
if not docker_path:
raise RuntimeError(
f"Docker is not installed. Please install Docker to use code execution with agent: {self.role}"
)

command = [str(docker_path), "info"]

# Validate subprocess command against governance policy
try:
self.security_config.governance.validate_subprocess(command)
except GovernanceError as e:
raise RuntimeError(
f"Governance policy blocked Docker validation for agent '{self.role}': {e}"
) from e

try:
subprocess.run( # noqa: S603
[str(docker_path), "info"],
command,
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
Expand Down
45 changes: 32 additions & 13 deletions lib/crewai/src/crewai/agents/crew_agent_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,22 @@ def _execute_single_native_tool_call(
structured_tool = structured
break

# Governance policy check (OWASP ASI02: Tool Misuse & Exploitation)
governance_blocked = False
if self.crew and hasattr(self.crew, "security_config"):
from crewai.security.governance import GovernanceError

try:
self.crew.security_config.governance.validate_tool(
func_name, args_dict or {}
)
except GovernanceError as gov_err:
governance_blocked = True
result = (
f"Tool execution blocked by governance policy. "
f"Tool: {func_name}. Reason: {gov_err.detail}"
)

hook_blocked = False
before_hook_context = ToolCallHookContext(
tool_name=func_name,
Expand All @@ -972,20 +988,23 @@ def _execute_single_native_tool_call(
crew=self.crew,
)
before_hooks = get_before_tool_call_hooks()
try:
for hook in before_hooks:
hook_result = hook(before_hook_context)
if hook_result is False:
hook_blocked = True
break
except Exception as hook_error:
if self.agent.verbose:
self._printer.print(
content=f"Error in before_tool_call hook: {hook_error}",
color="red",
)
if not governance_blocked:
try:
for hook in before_hooks:
hook_result = hook(before_hook_context)
if hook_result is False:
hook_blocked = True
break
except Exception as hook_error:
if self.agent.verbose:
self._printer.print(
content=f"Error in before_tool_call hook: {hook_error}",
color="red",
)

if hook_blocked:
if governance_blocked:
result = result # already set above
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code no-op self-assignment in governance branch

Low Severity

The line result = result is a self-assignment no-op that does nothing. This dead code makes the control flow harder to understand. A pass statement or a bare comment would more clearly communicate the intent that the governance-blocked result was already set above.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 27d5790. Configure here.

elif hook_blocked:
result = f"Tool execution blocked by hook. Tool: {func_name}"
elif max_usage_reached and original_tool:
result = f"Tool '{func_name}' has reached its usage limit of {original_tool.max_usage_count} times and cannot be used anymore."
Expand Down
17 changes: 16 additions & 1 deletion lib/crewai/src/crewai/security/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,22 @@
"""

from crewai.security.fingerprint import Fingerprint
from crewai.security.governance import (
GovernanceConfig,
GovernanceError,
HttpPolicy,
SubprocessPolicy,
ToolPolicy,
)
from crewai.security.security_config import SecurityConfig


__all__ = ["Fingerprint", "SecurityConfig"]
__all__ = [
"Fingerprint",
"GovernanceConfig",
"GovernanceError",
"HttpPolicy",
"SecurityConfig",
"SubprocessPolicy",
"ToolPolicy",
]
Loading
Loading