T05 · Unauthorized Access and Privilege Escalation
- Location
SKILL.md:133- Finding
Shared Shell Environment File Is Executed and Broadly Exported
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears intended for audio transcription, but its credential instructions are too broad and could expose or reuse local secrets beyond what transcription needs.
Review before installing. Use a dedicated ASR-only credential, avoid sourcing shared .env or shell startup files, do not copy TTS secrets into ASR variables, pin runtime dependencies, and confirm before sending sensitive audio to OpenAI or Volcano.
SKILL.md:133Shared Shell Environment File Is Executed and Broadly Exported
SKILL.md:181Cross-Service Credential Reuse Expands the Compromise Scope
SKILL.md:135Unpinned Runtime Installation of HTTP Client Dependencies
SKILL.md:187Unpinned Runtime Installation and Execution of OpenAI Whisper
The declared description presents a broader skill: take user audio/video, choose an ASR backend by source language, transcribe, and produce SRT. The actual code chunk is a narrow helper script that converts already-generated Volcano streaming ASR JSON into cleaned SRT subtitles. Its segmentation and subtitle formatting are consistent with part of the description ('outputs SRT with punctuation-bounded cues'), but the primary declared behavior includes provider selection and transcription, which are absent here. This is a material description/behavior mismatch, not merely an implementation detail.
The skill contains detailed instructions for accessing and reusing shared credentials from local files and shell configuration, including mapping ASR credentials from TTS secrets. This materially increases the chance of overbroad secret exposure and cross-service credential reuse, and in an agent environment it could encourage access to unrelated secrets beyond what is minimally required for the task.
- **build_srt_from_asr.py** also: splits cues on punctuation (HARD `。!?` flush; SOFT `,、;` flush past `--soft-min` chars; hard cap `--max-chars`), optionally strips all punctuation from the display (`--strip-punct`), drops 呃/嗯/唉 fillers, and collapses immediate duplicate short tokens (才才→才). Every cue is timed by its first/last word so it sits exactly on the spoken audio — no drift. **To avoid mid-sentence breaks, raise `--max-chars` so boundaries fall on punctuation rather than the char cap.**
- **Per-clip transcription:** transcribe each *clip's own* audio (16k mono PCM) so the SRT timestamps come out clip-relative.
- **Credentials:** live with the user (豆包语音引擎). Env names accepted by the script: `VOLC_ASR_APPID`/`VOLC_APPID` and `VOLC_ASR_ACCESS_TOKEN`/`VOLC_TOKEN`; `FFMPEG_BIN` optional.
- **This user's 火山 ASR and TTS share ONE credential set** — same appid + access token work for both services. They're stored in `~/code/.env` as `VOLC_TTS_APPID` / `VOLC_TTS_ACCESS_TOKEN` (plus `VOLC_APPID` in `~/.zshrc`), with `VOLC_ASR_APPID` / `VOLC_ASR_ACCESS_TOKEN` aliases appended pointing at the same values. So `set -a; source ~/code/.env; set +a` is enough — no separate ASR token to hunt for. If the aliases are ever missing, recreate them from the TTS values (they're the same secret).
- **Dead ends (don't retry):** MediaKit asr-subtitles (doc 6448/2381968) still needs a public URL *and* a separate MediaKit API key. The 录音文件识别 file API needs a public URL.
## Local Whisper as last resort
The skill clearly instructs shell execution, environment loading, and file generation, but it declares no tool scope or permissions boundary. That creates an implicit over-privilege situation where an agent may execute commands or access secrets without an explicit least-privilege contract, increasing the chance of unsafe secret access or filesystem modification during normal use.
The skill routes user audio to third-party ASR providers but does not prominently warn that potentially sensitive audio content will leave the local environment. For transcription workloads, uploaded media may contain private conversations, personal data, or confidential business information, so omission of this disclosure creates a real privacy and compliance risk.
Defaulting all Chinese audio to a specific external provider based on a standing preference removes informed provider choice and can silently send data to a service the current user did not select. This is mainly a privacy and consent issue rather than a technical compromise, but it becomes more sensitive when audio may contain regulated or confidential content.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
"temperature": "0.2", # enable fallback chain (anti-loop)
}
with open("chunk.mp3", "rb") as f:
r = httpx.post(
"https://api.openai.com/v1/audio/transcriptions",
headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"},
data=data,
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
}
with open("chunk.mp3", "rb") as f:
r = httpx.post(
"https://api.openai.com/v1/audio/transcriptions",
headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"},
data=data,
files={"file": ("chunk.mp3", f, "audio/mpeg")},
The skill explicitly instructs loading credentials from local environment files, including shell commands that source secrets into the process environment, without warning or containment guidance. In an agent setting, this can normalize broad secret exposure and make accidental leakage through logs, subprocesses, or unrelated commands more likely.
The unpinned uvx --with httpx dependency allows whatever current package version resolves at runtime, which can change behavior unexpectedly or pull a compromised upstream release. In an agent context that executes shell commands, this is a supply-chain risk because a future package update could introduce malicious code or unsafe defaults without any skill change.
Using uvx --from openai-whisper without a pinned version creates the same supply-chain and reproducibility problem, with the added risk that a model-wrapper CLI may change arguments or behavior across versions. Because this skill encourages direct command execution, unreviewed package updates could alter transcription logic or execute untrusted install-time code.
The script intentionally modifies recognized speech by deleting filler words and collapsing repeated short tokens before generating subtitles. In a skill advertised as producing a timestamped transcript/SRT in the source language, this creates integrity risk: the output is no longer a faithful transcript and can misrepresent speech content, especially in legal, medical, journalistic, or accessibility contexts.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def to_pcm(path):
if path.endswith(".pcm"):
return open(path, "rb").read()
out = subprocess.run([FFMPEG, "-v", "error", "-i", path, "-vn", "-ac", "1",
"-ar", "16000", "-f", "s16le", "-"], capture_output=True)
return out.stdout
The executable path comes from the FFMPEG_BIN environment variable and is passed directly to subprocess.run. If an attacker can influence the environment for this skill, they can cause execution of an arbitrary program instead of ffmpeg, leading to code execution under the skill's privileges.
def to_pcm(path):
if path.endswith(".pcm"):
return open(path, "rb").read()
out = subprocess.run([FFMPEG, "-v", "error", "-i", path, "-vn", "-ac", "1",
"-ar", "16000", "-f", "s16le", "-"], capture_output=True)
return out.stdout
The script sends user audio to a remote ASR provider over WebSocket without any explicit runtime consent check, warning, or privacy gate in code. In a transcription skill, audio commonly contains sensitive personal or confidential information, so silent third-party transmission creates a meaningful data privacy and compliance risk.
At L198-L202, the section labels the AI 润色 pass as the 'final step' after SRT assembly. But L214 instructs to run it 'before segmentation/clip-building,' which conflicts with the earlier sequencing and changes the stated operational intent.
The docstring states that cues are timed by first/last word so they sit exactly on the spoken audio with no drift. However, L046-L062 fabricates/fills missing word times, L076-L080 reassigns dropped-word timing to neighboring words, and L166-L168 enforces minimum duration and trims overlaps, so timing is adjusted heuristically rather than guaranteed exact.
The file-level docstring is written primarily in Chinese and frames this as the working path for use, without offering any language choice or documenting a justified locale restriction. Under the policy, forcing a specific language or locale in natural-language instructions without opt-in can be a violation.
No suspicious patterns detected.