CodeVetter · Repo Unpack · Risk map
openai/whisper
Highest-risk areas are (1) the `transcribe()` seek loop — a deliberately flattened, heuristic-heavy control flow the authors flag as obscure; (2) runtime code paths that execute or load external artifacts (ffmpeg subprocess, torch.load of checkpoint files, Triton JIT source patching); and (3) fragile fallbacks — numba JIT at import, the missing `regex` dependency, and silent error swallowing in the CLI. There is also a real latent bug in `_get_audio_features` returning a TypeError object instead of raising it.
- load_audio passes the user-supplied file path to an ffmpeg subprocess (list-form argv, no shell injection, but any local path incl. URLs/devices reaches ffmpeg); a CalledProcessError surfaces as RuntimeError with stderr.
- Checkpoint loading calls torch.load(weights_only=True) only when torch>=1.13; on older versions any local checkpoint path passed to load_model gets full pickle deserialization — arbitrary code execution risk for untrusted .pt files.
- Model download integrity relies on the SHA256 embedded in the URL path segment, verified before reuse and after download — but the URL itself is plain CDN state; a bad cached file triggers re-download, not a hard failure.
- The transcribe() main loop is acknowledged-fragile: an in-code comment says 'This loop is obscurely flattened to make the diff readable', and the seek is mutated by ~6 different mechanisms (segment_size fast-forward, last_timestamp seek, word-end seek, anomaly skips), making regressions easy and coverage nonexistent.
- DecodingTask._get_audio_features returns `TypeError(...)` as a value instead of raising it — a dead-branch bug where a dtype mismatch would propagate a TypeError object as audio_features.
- triton_ops generates the median-filter kernel by string-replacing LOAD_ALL_ROWS_HERE/BUBBLESORT_HERE placeholders inside a @triton.jit function's source, then mutating kernel.src/_unsafe_update_src — brittle across Triton versions; timing.py wraps calls in try/except (RuntimeError, CalledProcessError) with slow-path fallback.
- normalizers/basic.py imports the third-party `regex` package, which is absent from both pyproject dependencies and requirements.txt — importing whisper.normalizers.basic fails on a clean install unless regex arrives transitively.
- numba is a hard dependency imported at module top of timing.py and JIT-compiles dtw_cpu/backtrace at first call — first-call latency plus platform fragility for a function used only when word_timestamps is on.
- The CLI catches all exceptions per audio file and merely prints 'Skipping ...' — a fully-failed batch still exits 0, which can silently produce empty output directories in scripted pipelines.
- Default suppress_tokens='-1' expands to tokenizer.non_speech_tokens (music notes, brackets, symbols) plus all special/task tokens — a hard-coded suppression list that can mask legitimately-decoded characters, and any bug there degrades output quality rather than erroring.
- ApplyTimestampRules enforces timestamp/text alternation and monotonicity by in-place -inf masking per batch row; combined with the 'timestamp probability beats best text token' rule, subtle logic errors would produce shifted or looping timestamps rather than failures. (inferred)
- get_tokenizer/get_encoding/median_kernel are lru_cache'd singletons, so Tokenizer instances are shared process-wide; they are effectively immutable in practice, but any future mutability would leak state across calls. (inferred)