T09 · Insecure Skill Coding Practices
- Location
scripts/flow_voice.py:78- Finding
Unsafe Pickle Deserialization Through Traversable Profile Path
- Content
View full analysis
Vulnerability Details
File Location:
scripts/flow_voice.py, lines 78–86
Vulnerability Type: Unsafe deserialization combined with path traversal
Risk Level: HighVulnerable Code
python def load_profile(name: str) -> object: """Load a saved voice profile.""" path = PROFILES_DIR / f"{name}.pkl" if not path.exists(): print(f" ❌ No profile found for '{name}' at {path}", file=sys.stderr) print(f" 💡 Clone a voice first: --sample ref.wav --name {name}", file=sys.stderr) sys.exit(1) with open(path, "rb") as f: encoded = pickle.load(f) print(f" ✅ Profile loaded: {name}") return encodedTechnical Analysis
The
--voiceargument is inserted directly into a path without restricting path separators, parent-directory components, absolute paths, or other special path syntax. Appending.pkldoes not prevent traversal. For example, a profile name containing../../../../tmp/payloadcan resolve outsidePROFILES_DIR.The selected file is then passed to
pickle.load(). Python pickle is an executable serialization format: a crafted pickle can invoke attacker-selected callables during deserialization. Consequently, loading a profile is not merely a data operation and must only be performed on trusted, integrity-protected files.The combination of attacker-selectable file resolution and unsafe deserialization creates a direct local code-execution primitive when an attacker can supply the
--voicevalue and make a malicious pickle accessible to the process.Attack Path
- An attacker creates or places a malicious pickle file at a location readable by the Skill process, such as
/tmp/payload.pkl. - The attacker invokes the Skill, or induces the Agent to invoke it, with a traversal value such as:
text --voice ../../../../tmp/payload PROFILES_DIR / f"{name}.pkl"resolves to the external malicious file.
...[truncated 855 chars]
- An attacker creates or places a malicious pickle file at a location readable by the Skill process, such as
- Remediation
View remediation
Remediation Suggestions
- Replace pickle with a non-executable serialization format supported by the model representation, such as a strictly validated tensor or structured data format.
- If pickle cannot be removed, treat profile files as trusted executable artifacts and never load files based on unrestricted user paths.
- Restrict profile identifiers with an allowlist:
python import re if not re.fullmatch(r"[A-Za-z0-9_-]+", name): raise ValueError("Invalid profile name") - Resolve the candidate path and enforce containment:
python profiles_root = PROFILES_DIR.resolve() path = (profiles_root / f"{name}.pkl").resolve() if path.parent != profiles_root: raise ValueError("Profile path escapes the profile directory") - Ensure the profile directory and files are owned by the Agent account and are not writable by untrusted users.
- Consider signing profiles or storing an integrity hash in trusted metadata before loading them.
- Run voice processing in a sandbox with minimal filesystem, network, and subprocess permissions to limit the impact of any deserialization compromise.
