mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
security: gate custom code guardrail exec() behind LITELLM_ENABLE_CUSTOM_CODE_GUARDRAILS
CustomCodeGuardrail and the test endpoint both exec() user-supplied code in the same process. RestrictedPython sandbox escapes are well- documented. This makes custom code guardrails opt-in only by requiring LITELLM_ENABLE_CUSTOM_CODE_GUARDRAILS=true to be set explicitly. Also updates existing tests to enable the flag via monkeypatch.
This commit is contained in:
parent
0c81cd5a18
commit
67fb5adbfd
4 changed files with 30 additions and 0 deletions
|
|
@ -2071,6 +2071,14 @@ async def test_custom_code_guardrail(
|
|||
detail="Admin access required to test custom code guardrails",
|
||||
)
|
||||
|
||||
if os.getenv("LITELLM_ENABLE_CUSTOM_CODE_GUARDRAILS", "").lower() != "true":
|
||||
return TestCustomCodeGuardrailResponse(
|
||||
success=False,
|
||||
error="Custom code guardrails are disabled by default. "
|
||||
"Set LITELLM_ENABLE_CUSTOM_CODE_GUARDRAILS=true to enable.",
|
||||
error_type="compilation",
|
||||
)
|
||||
|
||||
EXECUTION_TIMEOUT_SECONDS = 5
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ Example: block when response rejects the user (input_type response only):
|
|||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import threading
|
||||
from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Type, cast
|
||||
|
||||
|
|
@ -143,8 +144,17 @@ class CustomCodeGuardrail(CustomGuardrail):
|
|||
"""Returns the config model for the UI."""
|
||||
return CustomCodeGuardrailConfigModel
|
||||
|
||||
@staticmethod
|
||||
def _require_custom_code_enabled() -> None:
|
||||
if os.getenv("LITELLM_ENABLE_CUSTOM_CODE_GUARDRAILS", "").lower() != "true":
|
||||
raise CustomCodeCompilationError(
|
||||
"Custom code guardrails are disabled by default. "
|
||||
"Set LITELLM_ENABLE_CUSTOM_CODE_GUARDRAILS=true to enable."
|
||||
)
|
||||
|
||||
def _do_compile(self) -> None:
|
||||
"""Internal compilation method without lock. Expected to run inside _compile_lock."""
|
||||
self._require_custom_code_enabled()
|
||||
exec_globals = build_sandbox_globals()
|
||||
compiled = compile_sandboxed(self.custom_code)
|
||||
exec(compiled, exec_globals) # noqa: S102
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ from litellm.proxy.guardrails.guardrail_hooks.custom_code import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def enable_custom_code_guardrails(monkeypatch):
|
||||
monkeypatch.setenv("LITELLM_ENABLE_CUSTOM_CODE_GUARDRAILS", "true")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def response_rejection_guardrail():
|
||||
"""Guardrail instance using the response-rejection custom code."""
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.proxy.guardrails.guardrail_hooks.custom_code.custom_code_guardrail import (
|
||||
|
|
@ -6,6 +8,11 @@ from litellm.proxy.guardrails.guardrail_hooks.custom_code.custom_code_guardrail
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def enable_custom_code_guardrails(monkeypatch):
|
||||
monkeypatch.setenv("LITELLM_ENABLE_CUSTOM_CODE_GUARDRAILS", "true")
|
||||
|
||||
|
||||
# str.mro() + generator gi_code + code.replace(co_names=...) + __setattr__
|
||||
# to swap a function's bytecode and read http_get's real builtins dict.
|
||||
BYTECODE_REWRITE_PAYLOAD = (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue