Compare commits

...

7 Commits

Author SHA1 Message Date
Rip&Tear
5bddfc6782 fix: replace unsafe ast.literal_eval() with secure alternative to prevent code injection
- Remove unsafe ast.literal_eval() usage in _validate_tool_input method
- Implement _safe_literal_parse() with strict input validation
- Add dangerous pattern detection to block __import__, exec, eval, lambda, etc.
- Support limited Python literal syntax (strings, numbers, booleans, None, lists, dicts)
- Only allow specific safe characters in input
- Maintain backward compatibility for valid tool inputs

Fixes security vulnerability where malicious tool_input could execute arbitrary Python code.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2025-10-12 19:33:28 +08:00
Rip&Tear
5e3f2e7be2 test 2025-10-12 16:59:57 +08:00
Rip&Tear
02c808eaae test: trigger local k8s deployment 2025-10-12 16:59:21 +08:00
Greyson LaLonde
7b550ebfe8 fix: inject tool repository credentials in crewai run command
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Notify Downstream / notify-downstream (push) Has been cancelled
Build uv cache / build-cache (3.10) (push) Has been cancelled
Build uv cache / build-cache (3.11) (push) Has been cancelled
Build uv cache / build-cache (3.12) (push) Has been cancelled
Build uv cache / build-cache (3.13) (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-10-10 15:00:04 -04:00
Greyson LaLonde
29919c2d81 fix: revert bad cron sched
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
This reverts commit b71c88814f.
2025-10-09 13:52:25 -04:00
Greyson LaLonde
b71c88814f fix: correct cron schedule to run every 5 days at specific dates 2025-10-09 13:10:45 -04:00
Rip&Tear
cb8bcfe214 docs: update security policy for vulnerability reporting
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
- Revised the security policy to clarify the reporting process for vulnerabilities.
- Added detailed sections on scope, reporting requirements, and our commitment to addressing reported issues.
- Emphasized the importance of not disclosing vulnerabilities publicly and provided guidance on how to report them securely.
- Included a new section on coordinated disclosure and safe harbor provisions for ethical reporting.

Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com>
2025-10-09 00:57:57 -04:00
4 changed files with 243 additions and 27 deletions

63
.github/security.md vendored
View File

@@ -1,27 +1,50 @@
## CrewAI Security Vulnerability Reporting Policy
## CrewAI Security Policy
CrewAI prioritizes the security of our software products, services, and GitHub repositories. To promptly address vulnerabilities, follow these steps for reporting security issues:
We are committed to protecting the confidentiality, integrity, and availability of the CrewAI ecosystem. This policy explains how to report potential vulnerabilities and what you can expect from us when you do.
### Reporting Process
Do **not** report vulnerabilities via public GitHub issues.
### Scope
Email all vulnerability reports directly to:
**security@crewai.com**
We welcome reports for vulnerabilities that could impact:
### Required Information
To help us quickly validate and remediate the issue, your report must include:
- CrewAI-maintained source code and repositories
- CrewAI-operated infrastructure and services
- Official CrewAI releases, packages, and distributions
- **Vulnerability Type:** Clearly state the vulnerability type (e.g., SQL injection, XSS, privilege escalation).
- **Affected Source Code:** Provide full file paths and direct URLs (branch, tag, or commit).
- **Reproduction Steps:** Include detailed, step-by-step instructions. Screenshots are recommended.
- **Special Configuration:** Document any special settings or configurations required to reproduce.
- **Proof-of-Concept (PoC):** Provide exploit or PoC code (if available).
- **Impact Assessment:** Clearly explain the severity and potential exploitation scenarios.
Issues affecting clearly unaffiliated third-party services or user-generated content are out of scope, unless you can demonstrate a direct impact on CrewAI systems or customers.
### Our Response
- We will acknowledge receipt of your report promptly via your provided email.
- Confirmed vulnerabilities will receive priority remediation based on severity.
- Patches will be released as swiftly as possible following verification.
### How to Report
### Reward Notice
Currently, we do not offer a bug bounty program. Rewards, if issued, are discretionary.
- **Please do not** disclose vulnerabilities via public GitHub issues, pull requests, or social media.
- Email detailed reports to **security@crewai.com** with the subject line `Security Report`.
- If you need to share large files or sensitive artifacts, mention it in your email and we will coordinate a secure transfer method.
### What to Include
Providing comprehensive information enables us to validate the issue quickly:
- **Vulnerability overview** — a concise description and classification (e.g., RCE, privilege escalation)
- **Affected components** — repository, branch, tag, or deployed service along with relevant file paths or endpoints
- **Reproduction steps** — detailed, step-by-step instructions; include logs, screenshots, or screen recordings when helpful
- **Proof-of-concept** — exploit details or code that demonstrates the impact (if available)
- **Impact analysis** — severity assessment, potential exploitation scenarios, and any prerequisites or special configurations
### Our Commitment
- **Acknowledgement:** We aim to acknowledge your report within two business days.
- **Communication:** We will keep you informed about triage results, remediation progress, and planned release timelines.
- **Resolution:** Confirmed vulnerabilities will be prioritized based on severity and fixed as quickly as possible.
- **Recognition:** We currently do not run a bug bounty program; any rewards or recognition are issued at CrewAI's discretion.
### Coordinated Disclosure
We ask that you allow us a reasonable window to investigate and remediate confirmed issues before any public disclosure. We will coordinate publication timelines with you whenever possible.
### Safe Harbor
We will not pursue or support legal action against individuals who, in good faith:
- Follow this policy and refrain from violating any applicable laws
- Avoid privacy violations, data destruction, or service disruption
- Limit testing to systems in scope and respect rate limits and terms of service
If you are unsure whether your testing is covered, please contact us at **security@crewai.com** before proceeding.

View File

@@ -775,3 +775,4 @@ A: Yes, CrewAI provides extensive beginner-friendly tutorials, courses, and docu
### Q: Can CrewAI automate human-in-the-loop workflows?
A: Yes, CrewAI fully supports human-in-the-loop workflows, allowing seamless collaboration between human experts and AI agents for enhanced decision-making.
# test

View File

@@ -1,10 +1,11 @@
import os
import subprocess
from enum import Enum
import click
from packaging import version
from crewai.cli.utils import read_toml
from crewai.cli.utils import build_env_with_tool_repository_credentials, read_toml
from crewai.cli.version import get_crewai_version
@@ -55,8 +56,22 @@ def execute_command(crew_type: CrewType) -> None:
"""
command = ["uv", "run", "kickoff" if crew_type == CrewType.FLOW else "run_crew"]
env = os.environ.copy()
try:
subprocess.run(command, capture_output=False, text=True, check=True) # noqa: S603
pyproject_data = read_toml()
sources = pyproject_data.get("tool", {}).get("uv", {}).get("sources", {})
for source_config in sources.values():
if isinstance(source_config, dict):
index = source_config.get("index")
if index:
index_env = build_env_with_tool_repository_credentials(index)
env.update(index_env)
except Exception: # noqa: S110
pass
try:
subprocess.run(command, capture_output=False, text=True, check=True, env=env) # noqa: S603
except subprocess.CalledProcessError as e:
handle_error(e, crew_type)

View File

@@ -1,6 +1,6 @@
import ast
import datetime
import json
import re
import time
from difflib import SequenceMatcher
from json import JSONDecodeError
@@ -44,6 +44,183 @@ OPENAI_BIGGER_MODELS = [
]
def _safe_literal_parse(input_str: str) -> Any:
"""
Safely parse a limited subset of Python literal syntax without using ast.literal_eval.
Only supports: strings (single/double quotes), numbers, booleans, None, lists, dicts.
Rejects any input that could lead to code execution.
Args:
input_str: String to parse
Returns:
Parsed Python object
Raises:
ValueError: If input contains unsafe or unsupported syntax
"""
if not isinstance(input_str, str):
raise ValueError("Input must be a string")
stripped = input_str.strip()
if not stripped:
raise ValueError("Input cannot be empty")
# Check for potentially dangerous patterns
dangerous_patterns = [
r'__.*__', # dunder methods
r'import\b', # import statements
r'exec\b', # exec function
r'eval\b', # eval function
r'lambda\b', # lambda functions
r'def\b', # function definitions
r'class\b', # class definitions
r'@\w+', # decorators
r'\.\.\.', # ellipsis (could be used in slicing)
r'->[^\]]*\]', # type hints in lists
]
for pattern in dangerous_patterns:
if re.search(pattern, stripped, re.IGNORECASE):
raise ValueError(f"Potentially dangerous pattern detected: {pattern}")
# Only allow specific characters
allowed_chars = r'[\s\w\.\-\+\*/\(\)\[\]\{\}:\'"<>!=,!=\?%&|~^`]'
if not re.fullmatch(f'{allowed_chars}*', stripped):
raise ValueError("Input contains unsupported characters")
# Try JSON parsing first (safest)
try:
return json.loads(stripped)
except (json.JSONDecodeError, TypeError):
pass
# Manual parsing for simple Python literals (JSON with single quotes, etc.)
try:
return _parse_python_literal_safe(stripped)
except Exception as e:
raise ValueError(f"Failed to parse input safely: {e}")
def _parse_python_literal_safe(input_str: str) -> Any:
"""
Parse a limited subset of Python literals safely.
Args:
input_str: String to parse
Returns:
Parsed Python object
"""
# Handle None
if input_str == 'None':
return None
# Handle booleans
if input_str == 'True':
return True
if input_str == 'False':
return False
# Handle numbers
if re.fullmatch(r'-?\d+$', input_str):
return int(input_str)
if re.fullmatch(r'-?\d+\.\d+$', input_str):
return float(input_str)
# Handle strings with single quotes (convert to JSON format)
if (input_str.startswith("'") and input_str.endswith("'")) or \
(input_str.startswith('"') and input_str.endswith('"')):
# Simple string - just remove quotes and escape common sequences
inner = input_str[1:-1]
# Handle common escape sequences safely
inner = inner.replace("\\'", "'").replace('\\"', '"').replace("\\\\", "\\")
return inner
# Handle lists
if input_str.startswith('[') and input_str.endswith(']'):
inner = input_str[1:-1].strip()
if not inner:
return []
items = _split_items_safe(inner)
return [_parse_python_literal_safe(item.strip()) for item in items]
# Handle dictionaries
if input_str.startswith('{') and input_str.endswith('}'):
inner = input_str[1:-1].strip()
if not inner:
return {}
pairs = _split_items_safe(inner)
result = {}
for pair in pairs:
if ':' not in pair:
raise ValueError(f"Invalid dict pair: {pair}")
key_str, value_str = pair.split(':', 1)
key = _parse_python_literal_safe(key_str.strip())
value = _parse_python_literal_safe(value_str.strip())
if not isinstance(key, str):
raise ValueError(f"Dict keys must be strings, got {type(key)}")
result[key] = value
return result
raise ValueError(f"Unsupported literal format: {input_str}")
def _split_items_safe(input_str: str, delimiter: str = ',') -> list[str]:
"""
Split a list or dict string into items, respecting nested structures.
Args:
input_str: String to split
delimiter: Delimiter to split on
Returns:
List of item strings
"""
items = []
current = []
depth = 0
in_string = False
string_char = None
i = 0
while i < len(input_str):
char = input_str[i]
# Handle string literals
if char in ('"', "'") and (i == 0 or input_str[i-1] != '\\'):
if not in_string:
in_string = True
string_char = char
elif char == string_char:
in_string = False
string_char = None
# Track nesting depth when not in strings
elif not in_string:
if char in ('[', '(', '{'):
depth += 1
elif char in (']', ')', '}'):
depth -= 1
elif char == delimiter and depth == 0:
items.append(''.join(current).strip())
current = []
i += 1
continue
current.append(char)
i += 1
if current:
items.append(''.join(current).strip())
return items
class ToolUsageError(Exception):
"""Exception raised for errors in the tool usage."""
@@ -524,14 +701,14 @@ class ToolUsage:
except (JSONDecodeError, TypeError):
pass # Continue to the next parsing attempt
# Attempt 2: Parse as Python literal
# Attempt 2: Parse as Python literal (safe alternative to ast.literal_eval)
try:
arguments = ast.literal_eval(tool_input)
arguments = _safe_literal_parse(tool_input)
if isinstance(arguments, dict):
return arguments
except (ValueError, SyntaxError):
repaired_input = repair_json(tool_input)
except ValueError:
# Continue to the next parsing attempt
pass
# Attempt 3: Parse as JSON5
try: