Skip to content

Mask --hf-token in OSError + stderr log to prevent secret leak - #72

Merged
zackees merged 1 commit into
zackees:mainfrom
victorkjung:upstream/mask-hf-token
Jun 3, 2026
Merged

zackees merged 1 commit into
zackees:mainfrom
victorkjung:upstream/mask-hf-token

Conversation

@victorkjung

Copy link
Copy Markdown
Contributor

run_insanely_fast_whisper calls subprocess.list2cmdline(cmd_list) to render the full insanely-fast-whisper command, prints it to stderr (the Running: ... line), and on non-zero exit raises OSError(f\"Failed to execute {cmd}\"). If --hf-token <hf_xxxx> is in cmd_list, the token leaks into:

  • Process stderr (worker stdout in any serverless/Docker context)
  • The OSError args, which propagates into:
    • Caller's error responses (RunPod Serverless's job status API surfaces the full traceback)
    • Any error-tracking / logging the caller has wired up

I personally hit this twice running transcribe-anything on RunPod Serverless before realizing the wrapper was the source — both times forcing a HuggingFace token rotation across multiple machines. The fix is local and tiny: regex-mask the token before any logging or raising.

The regex matches both --hf-token and --hf_token variants.

The subprocess itself still receives the raw token via cmd_list (which is passed to iso_env.open_proc unchanged), so functionality is untouched. Only the displayed/raised string is sanitized.

Diff summary

+    import re
...
+    cmd_safe = re.sub(r"(--hf[-_]token)\s+\S+", r"\1 <REDACTED>", cmd)
-    sys.stderr.write(f"Running:\n  {cmd}\n")
+    sys.stderr.write(f"Running:\n  {cmd_safe}\n")
...
-            msg = f"Failed to execute {cmd}\n "
+            msg = f"Failed to execute {cmd_safe}\n "

run_insanely_fast_whisper raises OSError with the full subprocess
command line on non-zero exit. That command line contains the user's
HuggingFace token verbatim (--hf-token hf_xxxx...). The OSError
propagates into:
  - RunPod's job status API response
  - Worker stdout (visible in Logs tab)
  - Any error tracking the caller wires up

Anyone with access to those surfaces sees the plaintext token.

Mask the token before logging-or-raising. Tokens passed via env
var to the subprocess are still functional — only the displayed
command line is sanitized.

Good candidate for an upstream PR to zackees/transcribe-anything.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@zackees

zackees commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Right direction — this is a legitimate security fix, not a stylistic change. Confirmed against main (commit 5c89267): src/transcribe_anything/insanely_fast_whisper.py:299 still writes the unmasked cmd to stderr, and line 288 raises OSError(f\"Failed to execute {cmd}\n \") containing the raw --hf-token <hf_xxxx> value.

Filed #93 to track the underlying vulnerability — this PR closes it.

A couple of small notes for the reviewer:

  • The regex r\"(--hf[-_]token)\s+\S+\" correctly handles both --hf-token (what insanely_fast_whisper.py:272 actually emits) and --hf_token (the alias accepted by whisper.py/whisperx.py).
  • The fix is local to the --device insane codepath. whisperx.py:467 and whisper.py build their own command strings; neither currently logs/raises the assembled command, so they don't leak today — but worth a quick audit before next release to be sure nobody added a debug print.
  • Functionality is preserved: cmd_list (passed to iso_env.open_proc) is unchanged; only the displayed/raised string is sanitized.

Recommend merging. Closes #93.

@zackees
zackees merged commit d7ba02e into zackees:main Jun 3, 2026
@zackees zackees mentioned this pull request Jun 4, 2026
4 of 7 tasks
zackees added a commit that referenced this pull request Jun 4, 2026
Headline features since 3.2.10:

- --device insane-flash: separate iso-env with pinned FlashAttention2 wheels
  (Windows x86_64, Linux x86_64/aarch64) on torch==2.7.0+cu128. Fails early
  with diagnostics when no controlled wheel is available, instead of silently
  falling back. (#90)
- --device whisperx: parallel additive backend with wav2vec2 alignment +
  pyannote diarization. Does NOT replace --device insane. (#87)
- --device sensevoice: FunASR/SenseVoiceSmall — non-autoregressive,
  multilingual (auto/zh/en/yue/ja/ko/nospeech), built-in fsmn-vad,
  optional cam++ diarization. (#101)
- --align: opt-in WhisperX wav2vec2 forced-alignment post-pass for
  --device insane and --device insane-flash. Per-word {word,start,end,
  score} data plus tightened segment timestamps. Reuses the whisperx
  iso-env, no new deps in insane. (#102)
- Read-only install support: backend venvs + static_ffmpeg cache moved
  from <site-packages>/transcribe_anything/venv/... to <user_cache_dir>/
  transcribe-anything/..., overridable via TRANSCRIBE_ANYTHING_CACHE_DIR.
  Unblocks Nix-store / OS-package / multi-user / read-only-container
  installs. (#100)
- Cloud / Serverless link to @victorkjung's RunPod fork for non-GPU
  users. (#94, #98)
- Security: mask --hf-token in insane backend stderr + OSError to prevent
  HuggingFace token leaks in serverless logs. (#72)
- audio.py: argv-list + shell=False + check=True for _convert_to_wav,
  closing the shell-injection surface in the URL-download path. (#96)

README "New in 4.0!" section expanded with the full feature set; existing
3.2 / 3.1 announcements preserved beneath it.

One-time upgrade cost: the venv-location move orphans existing 3.2 caches
at the old path. First run of each backend after upgrade re-downloads its
dependencies. Documented in the README.
zackees added a commit that referenced this pull request Jun 4, 2026
Headline features since 3.2.10:

- --device insane-flash: separate iso-env with pinned FlashAttention2 wheels
  (Windows x86_64, Linux x86_64/aarch64) on torch==2.7.0+cu128. Fails early
  with diagnostics when no controlled wheel is available, instead of silently
  falling back. (#90)
- --device whisperx: parallel additive backend with wav2vec2 alignment +
  pyannote diarization. Does NOT replace --device insane. (#87)
- --device sensevoice: FunASR/SenseVoiceSmall — non-autoregressive,
  multilingual (auto/zh/en/yue/ja/ko/nospeech), built-in fsmn-vad,
  optional cam++ diarization. (#101)
- --align: opt-in WhisperX wav2vec2 forced-alignment post-pass for
  --device insane and --device insane-flash. Per-word {word,start,end,
  score} data plus tightened segment timestamps. Reuses the whisperx
  iso-env, no new deps in insane. (#102)
- Read-only install support: backend venvs + static_ffmpeg cache moved
  from <site-packages>/transcribe_anything/venv/... to <user_cache_dir>/
  transcribe-anything/..., overridable via TRANSCRIBE_ANYTHING_CACHE_DIR.
  Unblocks Nix-store / OS-package / multi-user / read-only-container
  installs. (#100)
- Cloud / Serverless link to @victorkjung's RunPod fork for non-GPU
  users. (#94, #98)
- Security: mask --hf-token in insane backend stderr + OSError to prevent
  HuggingFace token leaks in serverless logs. (#72)
- audio.py: argv-list + shell=False + check=True for _convert_to_wav,
  closing the shell-injection surface in the URL-download path. (#96)

README "New in 4.0!" section expanded with the full feature set; existing
3.2 / 3.1 announcements preserved beneath it.

One-time upgrade cost: the venv-location move orphans existing 3.2 caches
at the old path. First run of each backend after upgrade re-downloads its
dependencies. Documented in the README.
zackees added a commit that referenced this pull request Jun 4, 2026
Headline features since 3.2.10:

- --device insane-flash: separate iso-env with pinned FlashAttention2 wheels
  (Windows x86_64, Linux x86_64/aarch64) on torch==2.7.0+cu128. Fails early
  with diagnostics when no controlled wheel is available, instead of silently
  falling back. (#90)
- --device whisperx: parallel additive backend with wav2vec2 alignment +
  pyannote diarization. Does NOT replace --device insane. (#87)
- --device sensevoice: FunASR/SenseVoiceSmall — non-autoregressive,
  multilingual (auto/zh/en/yue/ja/ko/nospeech), built-in fsmn-vad,
  optional cam++ diarization. (#101)
- --align: opt-in WhisperX wav2vec2 forced-alignment post-pass for
  --device insane and --device insane-flash. Per-word {word,start,end,
  score} data plus tightened segment timestamps. Reuses the whisperx
  iso-env, no new deps in insane. (#102)
- Read-only install support: backend venvs + static_ffmpeg cache moved
  from <site-packages>/transcribe_anything/venv/... to <user_cache_dir>/
  transcribe-anything/..., overridable via TRANSCRIBE_ANYTHING_CACHE_DIR.
  Unblocks Nix-store / OS-package / multi-user / read-only-container
  installs. (#100)
- Cloud / Serverless link to @victorkjung's RunPod fork for non-GPU
  users. (#94, #98)
- Security: mask --hf-token in insane backend stderr + OSError to prevent
  HuggingFace token leaks in serverless logs. (#72)
- audio.py: argv-list + shell=False + check=True for _convert_to_wav,
  closing the shell-injection surface in the URL-download path. (#96)

README "New in 4.0!" section expanded with the full feature set; existing
3.2 / 3.1 announcements preserved beneath it.

One-time upgrade cost: the venv-location move orphans existing 3.2 caches
at the old path. First run of each backend after upgrade re-downloads its
dependencies. Documented in the README.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants