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

Check out the documentation for more information.

PoC β€” NeMo setup_model() target-allowlist bypass

malicious_target_bypass.nemo is an uncompressed tar archive (tarfile.open(mode="w:"), the same mode NeMo itself uses to write .nemo files) containing:

  • model_config.yaml β€” a minimal config whose top-level target field is subprocess.Popen, a class completely unrelated to any NeMo model and not present in nemo.core.classes.common.ALLOWED_TARGET_PREFIXES.
  • model_weights.ckpt β€” a placeholder (not a real PyTorch checkpoint); it is never reached in this specific demonstration because subprocess.Popen has no .restore_from().

How this is meant to be used

python examples/asr/transcribe_speech.py model_path=malicious_target_bypass.nemo audio_dir=<any>

Expected effect, per the vulnerability described in the accompanying SUBMISSION.md:

  1. setup_model() (nemo/collections/asr/parts/utils/transcribe_utils.py:315-344) calls ASRModel.restore_from(restore_path=model_path, return_config=True), which extracts and parses model_config.yaml without ever calling _is_target_allowed() / safe_instantiate().
  2. classpath = model_cfg.target β†’ "subprocess.Popen".
  3. model_utils.import_class_by_path("subprocess.Popen") succeeds β€” this is the raw, unprotected function; it imports subprocess and resolves Popen with no allowlist check at all.
  4. subprocess.Popen.restore_from(restore_path=..., map_location=...) is then attempted and raises AttributeError (Popen has no restore_from), so the process crashes at this point.

The crash on step 4 is the intentionally non-destructive, minimum-guaranteed demonstration: it proves the import of an arbitrary, attacker-chosen, out-of-allowlist class already happened (step 3) before anything fails. Swapping subprocess.Popen for a module with dangerous import-time side effects, or for a compatible internal NeMo model class, changes the outcome without changing the underlying bug.

Caveat β€” not run end-to-end against a live NeMo installation

The exact bypass mechanism (import_class_by_path() accepting "subprocess.Popen" while _is_target_allowed() rejects it) was empirically verified by importing and calling the real, unmodified functions from this commit's nemo/utils/model_utils.py and nemo/core/classes/common.py directly (see attachments/poc_allowlist_bypass.py + attachments/run_output.txt in the main submission folder).

What was not independently re-verified is running transcribe_speech.py end-to-end against this exact .nemo file inside a full NeMo installation (setting up the complete pinned dependency stack β€” lightning, nv_one_logger*, megatron-core, etc. β€” proved impractical in the available verification environment due to unrelated third-party version incompatibilities in the nv_one_logger / lightning integration layer, not to anything about this bug). The static trace of setup_model() β†’ restore_from(..., return_config=True) β†’ load_config_and_state_dict() (nemo/core/connectors/save_restore_connector.py:98-202) was read in full and is quoted in the submission; only the live end-to-end run was not reproduced.

If it does not reproduce cleanly against a specific NeMo install, the standalone function-level PoC remains valid, verified, independent evidence of the root-cause bug regardless.

Downloads last month
3
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support