diff --git a/lib/crewai/src/crewai/knowledge/knowledge.py b/lib/crewai/src/crewai/knowledge/knowledge.py index b8d57bc05..b84e72afc 100644 --- a/lib/crewai/src/crewai/knowledge/knowledge.py +++ b/lib/crewai/src/crewai/knowledge/knowledge.py @@ -83,7 +83,9 @@ def _serialize_embedder_spec(value: Any) -> dict[str, Any] | None: def _validate_embedder_spec(value: Any) -> Any: """Resolve provider_class dotted-path dicts back to a class on restore.""" if isinstance(value, dict) and set(value.keys()) == {"provider_class"}: - if not os.environ.get("CREWAI_DESERIALIZE_CALLBACKS"): + from crewai.types.callback import _trusted_deserialize + + if not _trusted_deserialize(): raise ValueError( f"Refusing to resolve embedder provider_class " f"{value['provider_class']!r}: set " diff --git a/lib/crewai/src/crewai/types/callback.py b/lib/crewai/src/crewai/types/callback.py index 0f60883d1..ea89effdb 100644 --- a/lib/crewai/src/crewai/types/callback.py +++ b/lib/crewai/src/crewai/types/callback.py @@ -19,6 +19,15 @@ from pydantic import BeforeValidator, WithJsonSchema from pydantic.functional_serializers import PlainSerializer +_TRUSTED_DESERIALIZE_VALUES = frozenset({"1", "true", "yes"}) + + +def _trusted_deserialize() -> bool: + """Return True only if ``CREWAI_DESERIALIZE_CALLBACKS`` is an explicit yes.""" + raw = os.environ.get("CREWAI_DESERIALIZE_CALLBACKS", "") + return raw.strip().lower() in _TRUSTED_DESERIALIZE_VALUES + + def _is_non_roundtrippable(fn: object) -> bool: """Return ``True`` if *fn* cannot survive a serialize/deserialize round-trip. @@ -76,7 +85,7 @@ def string_to_callable(value: Any) -> Callable[..., Any]: raise ValueError( f"Invalid callback path {value!r}: expected 'module.name' format" ) - if not os.environ.get("CREWAI_DESERIALIZE_CALLBACKS"): + if not _trusted_deserialize(): raise ValueError( f"Refusing to resolve callback path {value!r}: " "set CREWAI_DESERIALIZE_CALLBACKS=1 to allow. " @@ -205,7 +214,7 @@ def _dotted_path_to_instance(value: Any) -> Any: raise ValueError( f"Invalid provider path {value!r}: expected 'module.name' format" ) - if not os.environ.get("CREWAI_DESERIALIZE_CALLBACKS"): + if not _trusted_deserialize(): raise ValueError( f"Refusing to resolve provider path {value!r}: " "set CREWAI_DESERIALIZE_CALLBACKS=1 to allow. "