Back to skill

Security audit

学习类视频转笔记工具

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches a video-to-notes tool, but it includes unrelated scripts that execute or overwrite files in a hard-coded external workspace and its note organizer can fabricate transcript-derived notes.

Review this before installing. The core video transcription workflow is recognizable, but remove or ignore the monitor scripts and hard-coded personal start script unless you fully trust that external workspace. Expect the tool to write tmp and done directories near your videos, retain intermediate transcripts/audio despite one doc claim about cleanup, and send local path metadata by email when the workflow completes.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (3)

T07 · Tool Hijacking and Spoofing

Error
Location
start_monitor.sh:1
Finding
Execution of an Unbundled Mutable Monitor Script and Broad Process Termination<![CDATA[ ## Vulnerability Details **File Location**: `start_monitor.sh`, lines 1–5 **Vulnerability Type**: Tool hijacking through execution of an external mutable script, combined with overly broad process termination **Risk Level**: High ### Vulnerable Code ```bash #!/bin/bash pkill -f monitor_web.py 2>/dev/null sleep 1 cd /home/fangjinan/.openclaw/workspace/skills/video-note-maker python3 monitor_web.py ``` ### Technical Analysis The launcher executes `monitor_web.py` from a hard-coded external workspace instead of resolving and executing a script bundled with the audited project. The referenced file is absent from the reviewed package, so its contents, provenance, and integrity cannot be established during the Skill audit. An actor who can modify the external `monitor_web.py` file can replace it with arbitrary Python code. The substituted code will execute with the privileges of the user who invokes `start_monitor.sh`. The command `pkill -f monitor_web.py` is also overly broad. The `-f` option matches against complete process command lines, so it may terminate unrelated processes merely because their command line contains `monitor_web.py`. The script does not verify process ownership, executable identity, or a Skill-specific PID before termination. ### Attack Path 1. An attacker obtains write access to `/home/fangjinan/.openclaw/workspace/skills/video-note-maker/monitor_web.py`, such as through another vulnerable local component, shared workspace permissions, or a compromised update process. 2. The attacker replaces or modifies `monitor_web.py` with an arbitrary Python payload. 3. The user invokes `start_monitor.sh`, believing it starts the legitimate monitoring component. 4. The launcher changes to the external directory and executes the attacker-modified file with the invoking user's privileges. 5. Before execution, `pkill -f monitor_web.py` may also terminate legitimate or unrelated processes whose command lines match that string. A denial-of-ser ...[truncated 774 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bundle `monitor_web.py` inside the reviewed project so its contents are included in security review and release integrity checks. 2. Resolve the script relative to the launcher rather than through a user-specific absolute path: ```bash SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" exec python3 "$SCRIPT_DIR/monitor_web.py" ``` 3. Verify the target is a regular file, is not a symbolic link, has an expected owner, and matches a release-provided cryptographic checksum before execution. 4. Replace `pkill -f` with a Skill-specific PID file stored in a permission-restricted runtime directory. 5. Before terminating a recorded PID, verify that it belongs to the current user and that `/proc/<pid>/exe` and its command line correspond to the expected bundled monitor. 6. Run the monitor with the minimum required filesystem and network permissions. 7. Fail closed when the expected bundled script or its integrity metadata is missing. ]]>

T07 · Tool Hijacking and Spoofing

Warning
Location
fix_monitor.py:1
Finding
Undocumented Overwrite of an External Workspace Tool<![CDATA[ ## Vulnerability Details **File Location**: `fix_monitor.py`, lines 1–40 **Vulnerability Type**: Modification of a local tool outside the packaged Skill without target validation or atomic update protection **Risk Level**: Medium ### Vulnerable Code ```python def fix_monitor_web(): import re with open('/home/fangjinan/.openclaw/workspace/skills/video-note-maker/monitor_web.py', 'r') as f: content = f.read() # 修复 updateStatusElement 函数 old_code = ''' function updateStatusElement(prefix, data) { const statusDot = document.getElementById(prefix + '-status .status-dot'); const statusText = document.getElementById(prefix + '-status .status-text'); const progressFill = document.getElementById(prefix + '-progress'); const progressText = document.getElementById(prefix + '-text'); statusDot.className = 'status-dot ' + data.status; statusText.textContent = data.text; progressFill.style.width = data.progress + '%'; progressText.textContent = data.text; }''' new_code = ''' function updateStatusElement(prefix, data) { const statusDot = document.querySelector('#' + prefix + '-status .status-dot'); const statusText = document.querySelector('#' + prefix + '-status .status-text'); const progressFill = document.querySelector('#' + prefix + '-progress'); const progressText = document.querySelector('#' + prefix + '-text'); if (statusDot) statusDot.className = 'status-dot ' + data.status; if (statusText) statusText.textContent = data.text; if (progressFill) progressFill.style.width = data.progress + '%'; if (progressText) progressText.textContent = data.text; }''' content = content.replace(old_code, new_code) with open('/home/fangjinan/.openclaw/workspace/skills/video ...[truncated 2378 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove this repair utility from the Skill unless modifying the monitor is an explicitly documented and necessary function. 2. Bundle the monitor and apply changes during a reviewed release rather than patching another installation at runtime. 3. If runtime patching is unavoidable, require the target path as an explicit argument and display it for confirmation. 4. Resolve the path with `Path.resolve()` and enforce that it remains inside an approved project directory. 5. Reject symbolic links and verify the expected file owner and permissions. 6. Verify a known pre-update checksum or version before applying the replacement. 7. Require that the expected source block occurs exactly once; otherwise, abort without writing. 8. Create a permission-preserving backup before modification. 9. Write the modified content to a temporary file in the same directory, flush and synchronize it, and use `os.replace()` for an atomic update. 10. Preserve the original file mode and avoid reporting success unless the replacement was actually applied. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:35
Finding
Unpinned Third-Party Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `README.md`, lines 35–42 **Vulnerability Type**: Unpinned dependency installation without integrity verification **Risk Level**: Medium ### Vulnerable Code ```bash # Ubuntu/Debian sudo apt-get install ffmpeg # Python dependencies pip3 install openai-whisper # Verify installation ffmpeg -version python3 -c "import whisper; print(whisper.__version__)" ``` The same unpinned Python installation command is repeated in the troubleshooting instructions at `README.md`, lines 134–136: ```bash pip3 install openai-whisper ``` ### Technical Analysis The installation instructions retrieve the latest available `openai-whisper` release and its transitive dependencies without a fixed version, lock file, or package hash. Consequently, the dependency graph can change after the Skill has been reviewed. Python packages and their dependencies can execute code during installation or when imported. If a future release or transitive dependency is compromised, users following these instructions may install and execute code that was not part of the audited project. The documentation also does not instruct users to use an isolated virtual environment. Installation into a shared user or system Python environment increases the effect of dependency conflicts and package replacement. No evidence was found that `openai-whisper` is currently malicious. The finding concerns the mutable and unverifiable supply-chain installation process. ### Attack Path 1. A user follows the documented command at a later date. 2. The package index resolves `openai-whisper` and its transitive dependencies to the versions available at that time. 3. A compromised or malicious future release enters the resolved dependency graph. 4. `pip` downloads and installs the unreviewed release without comparing it against project-provided hashes. 5. Installation-time behavior or a subsequent `import whisper` executes the compromised package with the user's privi ...[truncated 541 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Publish a reviewed, version-pinned dependency file rather than instructing users to install the latest release. 2. Pin all direct and transitive dependencies to exact versions. 3. Generate and distribute cryptographic hashes for every permitted artifact. 4. Require hash verification during installation, for example: ```bash python3 -m venv .venv . .venv/bin/activate python -m pip install --require-hashes -r requirements.txt ``` 5. Regenerate the lock file through a controlled review process when dependencies are upgraded. 6. Use an isolated virtual environment and avoid installing into the system Python environment. 7. Add automated dependency vulnerability and provenance scanning to the release process. 8. Pin or otherwise document reviewed ffmpeg package versions where reproducible deployment is required. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (36)

Tainted flow: 'CONFIG' from os.environ.get (line 18, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
}
        }
        headers = {"Content-Type": "application/json"}
        response = requests.post(CONFIG["feishu_webhook"], json=data, headers=headers, timeout=10)
        if response.status_code == 200:
            return True
        else:
Confidence
95% confidence
Finding
The skill transmits processing status to an arbitrary Feishu webhook taken from the environment, without meaningful user disclosure or consent. In this script's context, those messages include video filenames, progress, note paths, and completion details, which can leak potentially sensitive local metadata to an external service.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The tool claims to organize notes from transcripts but actually discards the transcription content and emits a hard-coded OSPF/ABR template. This is dangerous because it silently fabricates output while presenting it as transcript-derived, creating integrity failures, misinformation, and potential downstream misuse in educational or business contexts.

Intent-Code Divergence

High
Confidence
97% confidence
Finding
The generated Markdown explicitly states that the content is based on the video's transcript and preserves the teaching order, but the inserted body is static and unrelated to input. This compounds the integrity problem by adding deceptive provenance claims that may cause users to trust false notes and redistribute them as accurate summaries.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README documents that processing creates a tmp directory beside the source videos and later cleans temporary files, but it does not clearly warn users that the tool writes and deletes files inside the source directory tree. This can lead to accidental data loss, confusion during execution, or unsafe use on directories where users do not expect destructive behavior.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# Ubuntu/Debian
sudo apt-get install ffmpeg

# Python 依赖
pip3 install openai-whisper
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# Ubuntu/Debian
sudo apt-get install ffmpeg

# Python 依赖
pip3 install openai-whisper
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The configuration example sets `"language": "zh"`, which indicates a fixed language default. The document does not explain that users may choose another language or that this skill is intentionally limited to Chinese-only use, creating a locale-policy concern.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The documentation states the transcription language is fixed to Chinese ('zh') rather than offering a language choice. Under SQP-3, a forced language/locale is a policy issue unless the skill offers opt-in or clearly justifies the restriction as region-specific.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The workflow automatically emails completion details and includes sensitive metadata such as full video paths, output paths, timestamps, and potentially note-related content without a prominent privacy warning or explicit opt-in at the point of use. This can cause unintended disclosure of personal, corporate, or filesystem information to external services and recipients, especially because SMTP/IMAP use and recipient configuration are embedded into the workflow.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The --auto mode bypasses user confirmation and, according to the documented workflow, immediately performs file creation, transcript generation, note organization, and external notification. Without an explicit warning, users may trigger irreversible or privacy-impacting actions unintentionally, including sending metadata off-host and modifying local directories.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The config example sets `"language": "zh"`, which indicates a fixed locale choice embedded in the skill behavior. Because no user choice or opt-in is described nearby, this is a natural-language policy concern under SQP-3.

Intent-Code Divergence

Medium
Confidence
88% confidence
Finding
The note at L293 claims the tool will automatically clean the `tmp` directory after processing. However, the documented outputs and email content explicitly reference retained files under `tmp/{视频名}/`, including audio segments and `transcript_*.txt` files, with no documented cleanup step in the workflow. This is an active contradiction about whether intermediate artifacts persist.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The config hard-codes the language to "zh", which indicates the skill is restricted to Chinese without any visible option for the user to select another language. This is a natural-language policy concern because the file does not document an opt-in, fallback, or justified region-specific constraint.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script directly overwrites another skill file on disk using a hard-coded path and provides no user confirmation, backup, integrity check, or authorization control. This is dangerous because a user or agent running the script may unintentionally modify production skill code, and the same pattern could be repurposed to tamper with trusted files or silently introduce unwanted behavior.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script forcefully terminates any process whose command line matches 'monitor_web.py' without confirmation, scoping, or validation that it is the intended process instance. This can disrupt unrelated processes with the same name pattern and creates an unnecessary availability risk, especially in shared or multi-project environments.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The configuration forces Whisper transcription to use `zh`, which imposes a specific language/locale behavior on all runs. There is no CLI option or documented opt-in allowing users to choose another language, so this conflicts with the policy against forcing a locale without user choice.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
qqmail_user = os.environ.get("QQMAIL_USER", "your_email@example.com")
    
    try:
        result = subprocess.run([
            "python3", qqmail_script, "send",
            "--to", qqmail_user,
            "--subject", email_subject,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'qqmail_user' from os.environ.get (line 265, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
qqmail_user = os.environ.get("QQMAIL_USER", "your_email@example.com")
    
    try:
        result = subprocess.run([
            "python3", qqmail_script, "send",
            "--to", qqmail_user,
            "--subject", email_subject,
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.

Tainted flow: 'output_path' from os.environ.get (line 550, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
# 保存文件
    os.makedirs(done_dir, exist_ok=True)
    output_path = os.path.join(done_dir, f"{base_name}_学习笔记_整理版.md")
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(md_content)
    
    print(f"\n✅ 整理版笔记已保存:{output_path}")
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.

Tainted flow: 'output_path' from os.environ.get (line 550, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
# 保存文件
    os.makedirs(done_dir, exist_ok=True)
    output_path = os.path.join(done_dir, f"{base_name}_学习笔记_整理版.md")
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(md_content)
    
    print(f"\n✅ 整理版笔记已保存:{output_path}")
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.

Tainted flow: 'output_path' from os.environ.get (line 550, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
# 保存文件
    os.makedirs(done_dir, exist_ok=True)
    output_path = os.path.join(done_dir, f"{base_name}_学习笔记_整理版.md")
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(md_content)
    
    print(f"\n✅ 整理版笔记已保存:{output_path}")
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.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script automatically emails video metadata and local output paths after processing, without an explicit pre-send consent step. In this context, filenames and filesystem paths may reveal sensitive project names, personal data, or directory structures to external services or recipients.

External Transmission

Medium
Category
Data Exfiltration
Content
}
        }
        headers = {"Content-Type": "application/json"}
        response = requests.post(CONFIG["feishu_webhook"], json=data, headers=headers, timeout=10)
        if response.status_code == 200:
            return True
        else:
Confidence
95% confidence
Finding
This code performs external transmission to a Feishu webhook, sending status text that includes metadata about user files and processing activity. In a local media-processing skill, undisclosed network egress is more dangerous because users may expect transcription and note generation to remain local.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
'-b:a', CONFIG['audio_quality']['bitrate'],
            output_path
        ]
        subprocess.run(cmd, check=True)
        print(f"✅ 音频已提取:{output_path}")
        print(f"💡 使用 AAC 编码,文件大小约为 PCM_WAV 的 1/10")
        return output_path
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'cmd' from os.environ.get (line 412, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
'-b:a', CONFIG['audio_quality']['bitrate'],
            output_path
        ]
        subprocess.run(cmd, check=True)
        print(f"✅ 音频已提取:{output_path}")
        print(f"💡 使用 AAC 编码,文件大小约为 PCM_WAV 的 1/10")
        return output_path
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.

Static analysis

No suspicious patterns detected.