Back to skill

Security audit

外语视频→爆款切片→四平台发布一条龙

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly aligned with its video-editing purpose, but it handles social-account automation, browser/session cookies, and API credentials in ways that need review before installation.

Install only if you are comfortable with a Chinese-focused video repurposing workflow that may use browser cookies, social-platform login files, public posting automation, and an external Ofox image API. Use a dedicated browser/profile and social accounts, pin or review dependencies before setup, avoid the OPENROUTER_API_KEY fallback, test with one post first, and keep backups of media files before in-place processing.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/gen_covers_ai.py:36
Finding

OpenRouter API Credential Is Transmitted to an Unrelated Ofox Endpoint

Content
View full analysis

Vulnerability Details

File Location: scripts/gen_covers_ai.py, lines 36–46
Vulnerability Type: Cross-provider credential disclosure
Risk Level: High

Vulnerable Code

python
def key():
    k = os.environ.get("OFOX_API_KEY") or os.environ.get("OPENROUTER_API_KEY")
    if not k: raise SystemExit("缺 OFOX_API_KEY / OPENROUTER_API_KEY")
    return k

def gen(prompt, out, tries=6):
    for t in range(1, tries+1):
        try:
            payload = json.dumps({"model": MODEL, "prompt": prompt, "size": "1024x1536", "n": 1}).encode()
            req = urllib.request.Request(OFOX_URL, data=payload,
                headers={"Authorization": f"Bearer {key()}", "Content-Type": "application/json"})
            d = json.loads(urllib.request.urlopen(req, timeout=300).read())["data"][0]

The destination is statically defined earlier in the same file as:

python
OFOX_URL = "https://api.ofox.ai/v1/images/generations"

Technical Analysis

The key() function accepts either an OFOX_API_KEY or an OPENROUTER_API_KEY. Regardless of which credential is selected, gen() places it in a Bearer authorization header and sends it to the fixed Ofox endpoint.

API credentials are ordinarily scoped to a specific provider and trust boundary. Sending an OpenRouter credential to Ofox exposes that credential to an unrelated service, including its network termination, request logging, monitoring, and operational infrastructure. The fallback does not change the endpoint to OpenRouter and does not verify that the credential belongs to the selected provider.

This is a credential-confusion flaw rather than a hardcoded-secret issue: the user supplies the secret securely through an environment variable, but the application transmits it to the wrong party.

Attack Path

  1. A user configures OPENROUTER_API_KEY but does not configure OFOX_API_KEY.
  2. The user invokes scripts/gen_covers_ai.py.
  3. ` ...[truncated 961 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove OPENROUTER_API_KEY as a fallback when sending requests to Ofox:
    python
    def key():
        value = os.environ.get("OFOX_API_KEY")
        if not value:
            raise SystemExit("OFOX_API_KEY is required")
        return value
    
  2. If both providers are intended to be supported, bind each endpoint to its own credential:
    python
    PROVIDERS = {
        "ofox": {
            "url": "https://api.ofox.ai/v1/images/generations",
            "env": "OFOX_API_KEY",
        },
        "openrouter": {
            "url": "https://openrouter.ai/api/v1/...",
            "env": "OPENROUTER_API_KEY",
        },
    }
    
  3. Require an explicit provider selection rather than silently falling back between credentials.
  4. Validate that the selected endpoint host matches an allowlist for the selected provider before attaching the authorization header.
  5. Update the documentation so it does not imply that an OpenRouter credential is valid for Ofox.
  6. Advise users who previously ran the script with only OPENROUTER_API_KEY configured to revoke and rotate that key, then review provider usage and billing logs for unauthorized activity.

T08 · Insecure Dependencies

Warning
Location
scripts/setup.sh:8
Finding

Unpinned Third-Party Dependencies and Repository Code Are Installed from Mutable Sources

Content
View full analysis

Vulnerability Details

File Location: scripts/setup.sh, lines 8–38
Vulnerability Type: Unpinned dependency and software supply-chain exposure
Risk Level: Medium

Vulnerable Code

bash
if command -v brew >/dev/null; then
  brew list yt-dlp >/dev/null 2>&1 || brew install yt-dlp
  # 注意:homebrew 现在的 ffmpeg 是精简版不含 libass,必须装 ffmpeg-full
  brew list ffmpeg-full >/dev/null 2>&1 || brew install ffmpeg-full
  echo "    提示:把 ffmpeg-full 放进 PATH 前面:echo 'export PATH=\"/usr/local/opt/ffmpeg-full/bin:\$PATH\"' >> ~/.zshrc"
else
  echo "    非 macOS:自行安装 yt-dlp 和带 --enable-libass 的 ffmpeg"
fi

echo "==> 2) Whisper 转写引擎(faster-whisper, 装在独立 venv 避开 Python 版本问题)"
PY312="$(command -v python3.12 || true)"
if [ -n "$PY312" ]; then
  VENV="$HOME/.vvp-whisper"
  [ -d "$VENV" ] || "$PY312" -m venv "$VENV"
  "$VENV/bin/pip" install -q --upgrade pip
  "$VENV/bin/pip" install -q --prefer-binary faster-whisper pysocks "httpx[socks]"
  echo "    faster-whisper 装在 $VENV(用它的 python 跑转写)"
  echo "    模型首次会自动从 HuggingFace 下;国内网络不稳建议用 curl 续传预下到 ~/.cache/xh-models/"
else
  echo "    未找到 python3.12,请先装(brew install python@3.12),faster-whisper 在 3.14 上无 wheel"
fi

echo "==> 3) (可选)视频号自动发布: social-auto-upload"
read -r -p "    要安装视频号发布工具吗? [y/N] " ans
if [[ "${ans:-N}" =~ ^[Yy]$ ]]; then
  SAU="$HOME/social-auto-upload"
  [ -d "$SAU" ] || git clone --depth 1 https://github.com/dreammis/social-auto-upload.git "$SAU"
  if [ -n "$PY312" ]; then
    [ -d "$SAU/.venv" ] || "$PY312" -m venv "$SAU/.venv"
    "$SAU/.venv/bin/pip" install -q --upgrade pip
    "$SAU/.venv/bin/pip" install -q patchright loguru segno opencv-python-headless requests pyyaml schedule pillow
    "$SAU/.venv/bin/patchright" install chromium
  fi

Technical Analysis

The setup process installs Homebrew packages, Python packages, a Git repository, and a Chromium artifact without pinning reviewed versions, commits, or integrit ...[truncated 2931 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin every Python dependency to a reviewed version in a requirements file.
  2. Generate and enforce cryptographic hashes, for example with a locked requirements file and pip install --require-hashes.
  3. Pin social-auto-upload to a specific reviewed commit:
    bash
    git clone https://github.com/dreammis/social-auto-upload.git "$SAU"
    git -C "$SAU" checkout --detach "<reviewed-commit-sha>"
    
  4. Verify the checked-out commit against the expected full commit hash before creating the environment or executing repository code.
  5. Prefer signed releases or verified tags where the upstream project supports them.
  6. Pin the Patchright package and browser revision, and verify downloaded browser artifacts using publisher-provided checksums or signatures.
  7. Document the exact tested Homebrew formula versions. Where practical, use a lock mechanism or distribute checksums for expected binaries.
  8. Run browser automation in a dedicated, minimally privileged operating-system account or isolated container.
  9. Restrict permissions on session files, such as with mode 0600, and keep them outside source-controlled directories.
  10. Review dependency updates before changing pins, and use automated vulnerability and provenance scanning as part of that review.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (41)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the actual code primarily automates Xiaohongshu posting while the description frames it as one optional step in a broader media pipeline, users may not realize they are invoking a high-risk account automation function. Concealing or downplaying automated posting to third-party platforms is dangerous because it can trigger unauthorized publication, account sanctions, or unexpected authenticated actions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the actual code primarily automates Xiaohongshu posting while the description frames it as one optional step in a broader media pipeline, users may not realize they are invoking a high-risk account automation function. Concealing or downplaying automated posting to third-party platforms is dangerous because it can trigger unauthorized publication, account sanctions, or unexpected authenticated actions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the actual code primarily automates Xiaohongshu posting while the description frames it as one optional step in a broader media pipeline, users may not realize they are invoking a high-risk account automation function. Concealing or downplaying automated posting to third-party platforms is dangerous because it can trigger unauthorized publication, account sanctions, or unexpected authenticated actions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

If the actual code primarily automates Xiaohongshu posting while the description frames it as one optional step in a broader media pipeline, users may not realize they are invoking a high-risk account automation function. Concealing or downplaying automated posting to third-party platforms is dangerous because it can trigger unauthorized publication, account sanctions, or unexpected authenticated actions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the actual code primarily automates Xiaohongshu posting while the description frames it as one optional step in a broader media pipeline, users may not realize they are invoking a high-risk account automation function. Concealing or downplaying automated posting to third-party platforms is dangerous because it can trigger unauthorized publication, account sanctions, or unexpected authenticated actions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

If the actual code primarily automates Xiaohongshu posting while the description frames it as one optional step in a broader media pipeline, users may not realize they are invoking a high-risk account automation function. Concealing or downplaying automated posting to third-party platforms is dangerous because it can trigger unauthorized publication, account sanctions, or unexpected authenticated actions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

If the actual code primarily automates Xiaohongshu posting while the description frames it as one optional step in a broader media pipeline, users may not realize they are invoking a high-risk account automation function. Concealing or downplaying automated posting to third-party platforms is dangerous because it can trigger unauthorized publication, account sanctions, or unexpected authenticated actions.

Content

No source excerpt is available for this finding.

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Confidence
97% confidence
Finding

The skill instructs use of yt-dlp --cookies-from-browser chrome, which accesses authenticated browser cookie stores and reuses them for network requests. Even if intended to bypass bot checks for legitimate downloads, this is credential-sensitive behavior: it can expose session tokens, normalize browser data extraction, and widen the blast radius if the skill or surrounding tooling is abused or misconfigured.

Content

Scanner excerpt · SKILL.md (reported line 35)May include surrounding context.

化,需手机扫码登录)。

完整流程

步骤 0 · 确认意图与参数

  • 拿到链接/路径。超长视频(>30 min)先问清范围:整片 / 前 N 分钟 / 指定区间。在 CPU 上转写约 2x 实时,2 小时视频转写就要约 1 小时,要提醒用户。
  • 字幕类型若用户没明说,问:中文 / 中英双语。

步骤 1 · 下载

bash
yt-dlp --cookies-from-browser chrome -f "bv*[height<=1080]+ba/b[height<=1080]" \
  --merge-output-format mp4 -o "<tmp>/源.%(ext)s" "<URL>"
  • YouTube 报"Sign in to confirm you're not a bot"→ 加 --cookies-from-browser chrome。
  • 只要片段时可用 --download-sections "*0-180";整片就别用。
  • yt-dlp 偶尔不自动合并音视频流 → 用 ffmpeg-full 手动 -map 0:v:0 -map 1:a:0 -c copy 合并。

步骤 2 · 提取音频 + Whisper 转写

bash
ffmpeg-full -i 源.mp4 -vn -acodec libmp3lame -q:a 2 源.mp3
<whisper-venv>/bin/python transcribe_srt.py 源.mp3 --output 源.srt

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README describes the skill as converting foreign-language videos into Chinese-subtitled outputs and the example invocation specifically instructs Claude to produce Chinese-English bilingual content. This imposes a specific language/locale behavior in the skill description without indicating that users can choose another target language, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill declares broad operational behavior involving shell execution, network access, filesystem access, and environment-variable use, but it does not specify any tool scope or allowed-tools boundaries. That increases the chance the skill will be run with excessive privileges and makes review, sandboxing, and least-privilege enforcement much harder.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The description lists activation phrases such as “翻译视频并切片” and especially “做爆款切片,” which are generic task requests rather than narrowly scoped invocation triggers. The file does not provide exclusion conditions or negative examples, so the skill could be invoked unintentionally for broad video-editing requests.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The description states the skill converts content into “中文字幕成片,” and later workflow steps prescribe Chinese or Chinese-first outputs as defaults. This is a language/locale constraint presented as the standard behavior without clearly offering user opt-in at the entry point.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/gen_covers_ai.py (reported line 14)May include surrounding context.

python
"""
import argparse, base64, json, os, time, urllib.request

OFOX_URL = "https://api.ofox.ai/v1/images/generations"
MODEL = "gpt-image-2"   # 注意:gpt-image-1 在 Ofox 上是 404

# 两种已验证有效的爆款风格模板(科技/AI 赛道)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The embedded style prompts explicitly require '简体中文' text in generated covers, which imposes a fixed language/locale behavior. The file does not indicate that this is optional, user-selected, or justified as a region-specific tool, so it conflicts with the policy against forced language without opt-in.

Content

No source excerpt is available for this finding.

Tainted flow: 'd' from urllib.request.urlopen (line 46, network input) → urllib.request.urlopen (network output)

Medium
Category
Data Flow
Confidence
89% confidence
Finding

The script trusts a URL returned by the external API and performs a second urlopen on d['url'] with no host allowlist, scheme validation, or redirect restrictions. If the upstream service is compromised or manipulated, this can turn the client into a server-side request gadget that fetches unexpected resources, including internal endpoints or very large payloads.

Content

Scanner excerpt · scripts/gen_covers_ai.py (reported line 47)May include surrounding context.

python
req = urllib.request.Request(OFOX_URL, data=payload,
                headers={"Authorization": f"Bearer {key()}", "Content-Type": "application/json"})
            d = json.loads(urllib.request.urlopen(req, timeout=300).read())["data"][0]
            data = base64.b64decode(d["b64_json"]) if d.get("b64_json") else urllib.request.urlopen(d["url"]).read()
            open(out, "wb").write(data); return True
        except Exception as e:
            print(f"    重试{t}: {str(e)[:70]}", flush=True); time.sleep(4)

Tainted flow: 'out' from open (line 70, file read) → open (file write)

Medium
Category
Data Flow
Confidence
93% confidence
Finding

The output path is derived from untrusted config data via c['name'] and joined directly into out_dir without validating path components. An attacker controlling covers.json can use path traversal or absolute-path tricks to overwrite arbitrary files writable by the user, and the script writes attacker-influenced binary data to that location.

Content

Scanner excerpt · scripts/gen_covers_ai.py (reported line 48)May include surrounding context.

python
headers={"Authorization": f"Bearer {key()}", "Content-Type": "application/json"})
            d = json.loads(urllib.request.urlopen(req, timeout=300).read())["data"][0]
            data = base64.b64decode(d["b64_json"]) if d.get("b64_json") else urllib.request.urlopen(d["url"]).read()
            open(out, "wb").write(data); return True
        except Exception as e:
            print(f"    重试{t}: {str(e)[:70]}", flush=True); time.sleep(4)
    return False

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
82% confidence
Finding

The script allows the ffmpeg executable path to come directly from configuration and then executes it. Although shell injection is avoided by passing an argument list, an attacker who can modify the config could point 'ffmpeg' to an arbitrary local executable and achieve arbitrary code execution under the script's privileges.

Content

Scanner excerpt · scripts/prepend_covers.py (reported line 11)May include surrounding context.

python
def find_ffmpeg(cfg):
    for c in (cfg.get("ffmpeg"), "/usr/local/opt/ffmpeg-full/bin/ffmpeg",
              "/opt/homebrew/opt/ffmpeg-full/bin/ffmpeg", "ffmpeg"):
        if c and subprocess.run([c,"-version"],capture_output=True).returncode==0:
            return c
    sys.exit("找不到 ffmpeg")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/prepend_covers.py (reported line 34)May include surrounding context.

python
"-filter_complex",vf,"-map","[outv]","-map","[outa]",
             "-c:v","libx264","-preset","veryfast","-crf","23","-c:a","aac","-b:a","128k",
             "-movflags","+faststart",tmp]
        r=subprocess.run(cmd,capture_output=True,text=True)
        if r.returncode: print(f"[{i}] ❌ {name}\n{r.stderr[-400:]}")
        else: os.replace(tmp,clip_mp4); print(f"[{i}] ✅ {name} 已加封面帧")
    print("=== 封面帧完成 ===")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/render_covers.py (reported line 55)May include surrounding context.

python
"-filter_complex",vf,"-map","[outv]","-map","[outa]",
             "-c:v","libx264","-preset","veryfast","-crf","23","-c:a","aac","-b:a","128k",
             "-movflags","+faststart",tmp]
        r=subprocess.run(cmd,capture_output=True,text=True)
        if r.returncode: print(f"[{i}] ❌ {name}\n{r.stderr[-400:]}")
        else: os.replace(tmp,clip_mp4); print(f"[{i}] ✅ {name} 已加封面帧")
    print("=== 封面帧完成 ===")

Tainted flow: 'cmd' from open (line 30, file read) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/prepend_covers.py (reported line 34)May include surrounding context.

python
"-filter_complex",vf,"-map","[outv]","-map","[outa]",
             "-c:v","libx264","-preset","veryfast","-crf","23","-c:a","aac","-b:a","128k",
             "-movflags","+faststart",tmp]
        r=subprocess.run(cmd,capture_output=True,text=True)
        if r.returncode: print(f"[{i}] ❌ {name}\n{r.stderr[-400:]}")
        else: os.replace(tmp,clip_mp4); print(f"[{i}] ✅ {name} 已加封面帧")
    print("=== 封面帧完成 ===")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script replaces the original video file in place with os.replace(tmp, clip_mp4) after processing, without an explicit confirmation or automatic backup. In a bulk publishing pipeline, this can cause irreversible data loss or corruption if processing succeeds incorrectly, a wrong cover is used, or ffmpeg produces unexpected output.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/publish_shipinhao.py (reported line 44)May include surrounding context.

python
cfg=json.load(open(a.config,encoding="utf-8"))
    account=os.path.expanduser(cfg.get("account_file",
        str(__import__("pathlib").Path(BASE_DIR)/"cookies"/"tencent_uploader"/"account.json")))
    vdir=os.path.expanduser(cfg["video_dir"])
    items=cfg["items"]
    idxs=parse_idx(a.idx,len(items))

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language description states the tool adds a Chinese hook title to each clip, and the rest of the usage text is only in Chinese. This imposes a specific language/locale behavior without offering user opt-in or documenting a justified region-specific constraint.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/render_clips.py (reported line 26)May include surrounding context.

python
if not c:
            continue
        try:
            subprocess.run([c, "-version"], capture_output=True, check=True)
            # 验证带 libass
            out = subprocess.run([c, "-hide_banner", "-version"], capture_output=True, text=True).stdout
            return c

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/render_clips.py (reported line 28)May include surrounding context.

python
try:
            subprocess.run([c, "-version"], capture_output=True, check=True)
            # 验证带 libass
            out = subprocess.run([c, "-hide_banner", "-version"], capture_output=True, text=True).stdout
            return c
        except Exception:
            continue

Static analysis

No suspicious patterns detected.