When designing systems that handle sensitive operations, always default to the most secure behavior rather than prioritizing convenience. This practice applies to error handling, execution environments, and security-critical fallbacks.
When designing systems that handle sensitive operations, always default to the most secure behavior rather than prioritizing convenience. This practice applies to error handling, execution environments, and security-critical fallbacks.
Key principles to follow:
Sanitize error responses: Never expose internal exception details or stack traces in API responses that could reveal implementation details to potential attackers.
Require explicit opt-in for reduced security: Don’t silently fall back to less secure modes of operation; require explicit configuration through environment variables or parameters.
Log security-relevant decisions: Ensure security-related fallbacks are clearly logged for monitoring and debugging.
Example of insecure error handling:
except Exception as e:
return JSONResponse(
content=JSONRPCResponse(
id=request_id,
error=InternalError(data=str(e)), # Exposes potentially sensitive details
),
status_code=500,
)
Secure implementation:
except Exception as e:
# Log complete details for internal use
self.logger.exception(f"Error handling {method} request")
# Return sanitized response to external users
return JSONResponse(
content=JSONRPCResponse(
id=request_id,
error=InternalError(data="An internal server error occurred"),
),
status_code=500,
)
Example of insecure fallback:
unsafe_mode = not self.check_docker_available()
# Silently proceeds with unsafe execution
Secure implementation:
if not self.check_docker_available():
if os.getenv("CREWAI_GUARDRAIL_EXECUTION_MODE") == "allow_unsafe":
self.logger.warning("Docker unavailable. Falling back to unsafe execution mode.")
self.unsafe_mode = True
else:
raise SecurityError("Cannot execute code safely. Docker unavailable and unsafe execution not explicitly enabled.")
Enter the URL of a public GitHub repository