Skip to content

Security: unsafe YAML config loading enables arbitrary code executionΒ #311

Description

@Ano1X8

πŸ› Bug

Loading a model can execute arbitrary code. read_yaml() in utils/infer_utils.py (~line 319) parses a model's
config.yaml with PyYAML's UNSAFE full loader β€” yaml.load(f, Loader=yaml.Loader). yaml.Loader constructs arbitrary
Python objects from YAML tags (e.g. an os.system apply tag), so a crafted config.yaml runs shell commands at parse
time; when the model is loaded, before/independent of the ONNX weights.

This is deserialization of untrusted data (CWE-502): a user who loads a shared or attacker-published SenseVoice model gets arbitrary code execution.

I'm keeping this public report to the diagnosis and withholding a working proof-of-concept, since the code is
currently unpatched. Full reproduction available privately if you enable private vulnerability reporting or share a contact email.

To Reproduce

Exact command (benign, this is the load path that reaches the sink):

  1. Run:
    python -c "from model import SenseVoiceSmallONNX; SenseVoiceSmallONNX('<model_dir_or_downloaded_model>')"
    (any public entrypoint that loads the ONNX model calls read_yaml() on its config.yaml)
  2. read_yaml() parses config.yaml via yaml.load(f, Loader=yaml.Loader). If that config.yaml contains a
    Python-object YAML tag, the tag executes at parse time.

The malicious config.yaml / turnkey PoC is withheld here to avoid publishing a working exploit before a fix. I'll
share the full step-by-step reproduction privately.

Code sample

The sink, from the current source (utils/infer_utils.py ~L319):
def read_yaml(yaml_path):
with open(str(yaml_path), "rb") as f:
data = yaml.load(f, Loader=yaml.Loader) # <-- unsafe: executes Python-object YAML tags
return data

Reached on the public load path when the ONNX model is loaded, e.g. SenseVoiceSmallONNX(model_dir), where model_dir may be a downloaded/attacker-supplied bundle whose config.yaml is untrusted. A config.yaml carrying a Python-object tag runs code inside read_yaml(). (Payload withheld.)

Expected behavior

Loading a model configuration should only read data. Parsing a model's config.yaml must never construct arbitrary Python objects or execute code.

Environment

  • OS: platform-independent (Python/PyYAML issue; reproduced on Linux)
  • FunASR Version: N/A β€” this is SenseVoice (all versions, current main)
  • ModelScope Version: N/A (issue is in the config parser, independent of model source)
  • PyTorch Version: N/A (weights are ONNX; sink fires before/independent of weight load)
  • How you installed: source / the SenseVoice ONNX runtime
  • Python version: 3.x
  • GPU: N/A (parse-time issue, device-independent)
  • CUDA/cuDNN version: N/A
  • Docker version: N/A
  • Any other relevant information: sink at utils/infer_utils.py read_yaml(), yaml.load(f, Loader=yaml.Loader)

Additional context

Suggested fix (one line): replace Loader=yaml.Loader with Loader=yaml.SafeLoader in utils/infer_utils.py
read_yaml() β€” configs are plain mappings/lists/scalars, so it's a drop-in with no functional change.

Severity CVSS 3.1 8.4
(AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H); CVE requested (coordinated disclosure).

The same read_yaml is vendored from modelscope/FunASR, reported separately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions