Back to skill

Security audit

speech2text

Security checks for vulnerabilities and agentic risk

Overview

This speech-to-text skill does what it claims, but it can silently pick and transcribe the newest local inbound audio file when the current request has no attachment, which may expose someone else’s recording.

Review before installing, especially in shared or multi-user OpenClaw environments. The skill should be changed to process only audio explicitly attached to the current request, avoid returning local filesystem paths, and use safe temporary files for conversion before it is treated as low risk.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
__init__.py:105
Finding
Unscoped Audio Fallback Can Transcribe Another User's Recording## Vulnerability Details **File Location**: `__init__.py`, lines 105-124 and 177-179 **Vulnerability Type**: Missing resource ownership and request-context validation **Risk Level**: High ### Vulnerable Code ```python def find_voice_files(media_dir: str = None): """Find the newest voice file.""" if media_dir is None: media_dir = os.path.join( os.path.expanduser('~'), '.openclaw', 'media', 'inbound' ) if not os.path.exists(media_dir): return None ogg_files = list(Path(media_dir).glob('*.ogg')) if not ogg_files: return None latest = max(ogg_files, key=lambda f: f.stat().st_mtime) return str(latest) ``` ```python if not voice_file: voice_file = find_voice_files() ``` ### Technical Analysis When the current request has no recognized audio attachment, the skill searches a shared inbound media directory and selects the most recently modified `.ogg` file. It does not verify that the selected file belongs to the current user, conversation, tenant, or request. File recency is not a security boundary. In a shared or concurrent deployment, the newest file may have been uploaded by another user. The selected recording is passed to the transcription function, and the resulting transcript and source path are returned to the caller. ### Attack Path 1. A victim uploads an `.ogg` voice recording, causing it to be stored under `~/.openclaw/media/inbound`. 2. An attacker invokes the skill without supplying an audio attachment. 3. The attachment lookup leaves `voice_file` unset. 4. The fallback calls `find_voice_files()`. 5. The function selects the globally newest `.ogg` file, potentially the victim's recording. 6. The skill transcribes that recording and returns its contents and filesystem path to the attacker. ### Impact Assessment An unauthenticated or lower-privileged caller who ...[truncated 324 chars]
Remediation
## Remediation Suggestions - Remove the global newest-file fallback from the request-facing `main` function. - Require an attachment explicitly associated with the current authenticated request. - Validate attachment ownership, tenant, conversation, and message identifiers before accessing the file. - Resolve the attachment path with `Path.resolve()` and verify that it remains inside a per-request or per-tenant media directory. - Reject symbolic links and files not created or registered by the trusted attachment subsystem. - Return an error when no request-bound recording is available rather than searching a shared directory. - Avoid returning internal filesystem paths to callers unless they are explicitly required and authorized.

T09 · Insecure Skill Coding Practices

Warning
Location
__init__.py:54
Finding
Predictable Conversion Destination Allows Existing Files to Be Overwritten## Vulnerability Details **File Location**: `__init__.py`, lines 54-73 and 92-95 **Vulnerability Type**: Unsafe output-file handling and unrestricted overwrite **Risk Level**: Medium ### Vulnerable Code ```python def convert_to_wav(input_path: str, output_path: str = None) -> str: """Convert audio to WAV format.""" if output_path is None: output_path = input_path.replace('.ogg', '.wav').replace('.mp3', '.wav') ffmpeg_path = find_ffmpeg() if not ffmpeg_path: raise RuntimeError('ffmpeg was not found') env = os.environ.copy() env['PATH'] = ffmpeg_path + ';' + env.get('PATH', '') result = subprocess.run( ['ffmpeg', '-i', input_path, '-ar', '16000', '-ac', '1', output_path, '-y'], capture_output=True, env=env ) ``` ```python ext = os.path.splitext(audio_path)[1].lower() if ext in ['.ogg', '.mp3', '.m4a']: wav_path = audio_path.replace(ext, '.wav') convert_to_wav(audio_path, wav_path) ``` ### Technical Analysis The output path is derived predictably by replacing the input extension with `.wav`. FFmpeg is then invoked with `-y`, which unconditionally overwrites an existing destination. The request handler accepts attachment paths from context without canonical-path confinement. If an attacker can influence that path and the process has write access to the corresponding directory, conversion can replace an existing same-basename `.wav` file. A symbolic link or other filesystem redirection at the predictable destination may further redirect the write, subject to operating-system and FFmpeg behavior. The subprocess uses an argument list and does not use `shell=True`, so this is not shell command injection. The vulnerability is unsafe destination-file handling. ### Attack Path 1. An attacker identifies or arranges an input path such as `target.ogg`. 2. A writable file or link already exists at the derived destination ...[truncated 848 chars]
Remediation
## Remediation Suggestions - Create conversion outputs with `tempfile.NamedTemporaryFile` or `tempfile.mkstemp` in a dedicated private temporary directory. - Use randomized filenames rather than deriving the destination from attacker-influenced input. - Remove unconditional FFmpeg overwrite behavior or fail if the destination already exists. - Canonicalize input paths and require them to remain inside an approved, request-specific media directory. - Reject symbolic links and validate files using secure descriptor-based operations where supported. - Run conversion under a restricted service account with access only to dedicated media and temporary directories. - Delete temporary converted files after transcription in a `finally` block.

T08 · Insecure Dependencies

Note
Location
SKILL.md:20
Finding
Third-Party Dependencies Are Installed Without Version or Integrity Pinning## Vulnerability Details **File Location**: `SKILL.md`, lines 20-24; dependency installation guidance is also repeated in `__init__.py`, lines 159-163 **Vulnerability Type**: Unpinned and non-reproducible dependency installation **Risk Level**: Low ### Vulnerable Code ```bash pip install faster-whisper pydub ``` ### Technical Analysis The installation instructions retrieve the latest available releases of `faster-whisper` and `pydub` without exact version constraints or package hashes. Consequently, installations performed at different times may execute different dependency code despite using the same reviewed skill source. This does not prove that either named package is malicious. However, the installation procedure lacks controls against unexpected upstream releases, compromised publisher accounts, registry compromise, or dependency-chain changes. Python packages and their transitive dependencies may execute code during installation or later when imported. ### Attack Path 1. A maintainer or deployment process follows the documented installation command. 2. The package index resolves the names to the latest releases and their current transitive dependencies. 3. An upstream package, publisher account, release artifact, or dependency chain has been compromised or has introduced unsafe behavior. 4. The unpinned installation retrieves the affected release because no reviewed version or integrity hash is enforced. 5. The dependency code executes during installation, import, model loading, or audio processing with the privileges of the skill environment. ### Impact Assessment A compromised dependency could execute arbitrary code with the privileges of the installation or runtime account. Potential consequences include access to readable files, environment variables, media recordings, model data, and network resources available to that account. Exploitation depends on an upstream supply-chain event; no malicious dependency ...[truncated 37 chars]
Remediation
## Remediation Suggestions - Pin every direct dependency to an exact reviewed version. - Generate and commit a lockfile that includes resolved transitive dependencies. - Enforce cryptographic hashes, for example with a hash-locked requirements file and `pip install --require-hashes`. - Install only from an explicitly configured trusted package index. - Scan direct and transitive dependencies for known vulnerabilities before release and during continuous integration. - Review dependency updates before changing the lockfile. - Remove `pydub` from installation instructions if it is not required by the implementation. - Build and deploy dependencies in an isolated, least-privileged environment.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (8)

Env Variable Harvesting

High
Category
Data Exfiltration
Content
if not ffmpeg_path:
        raise RuntimeError('未找到 ffmpeg,请安装 ffmpeg')
    
    env = os.environ.copy()
    env['PATH'] = ffmpeg_path + ';' + env.get('PATH', '')
    
    result = subprocess.run(
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The phrase '或者手动调用 skill' does not specify what exact command, phrase, or context should invoke the skill. This ambiguity can cause unintended activation because users and orchestrators are not given clear boundaries for when the skill should or should not run.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The natural-language configuration states '默认语言: zh (中文)', which indicates the skill defaults to a specific language/locale. The file does not mention user choice, auto-detection, or opt-in, so this may violate language/locale policy requirements.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The skill sets LANGUAGE = 'zh' and uses that default for transcription, which forces a specific language/locale choice unless callers explicitly override it. This is a natural-language policy concern because the file does not indicate user choice or documented justification for restricting recognition to Chinese.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
env = os.environ.copy()
    env['PATH'] = ffmpeg_path + ';' + env.get('PATH', '')
    
    result = subprocess.run(
        ['ffmpeg', '-i', input_path, '-ar', '16000', '-ac', '1', output_path, '-y'],
        capture_output=True,
        env=env
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The skill scans a default local inbound media directory outside the explicit message context and selects the newest .ogg file. This can cause the skill to access and transcribe audio unrelated to the current user request, creating a privacy boundary violation and unintended data exposure.

Context-Inappropriate Capability

Medium
Confidence
99% confidence
Finding
When no attachment is present, the main entrypoint silently falls back to transcribing the latest local voice file. This may disclose the contents of another user's or another session's audio without authorization, especially in shared or multi-tenant environments.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill automatically locates and transcribes the latest inbound voice file without user warning or confirmation. In a messaging/agent skill context, this increases the chance of covert processing of private audio and makes accidental over-collection more likely.

Static analysis

No suspicious patterns detected.