Back to skill

Security audit

Audio2Text

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but it can send recordings and API keys to user-supplied network endpoints without validation.

Install only if you are comfortable sending selected recordings and resulting transcripts to Tinrec's cloud service. Do not use this with confidential or regulated audio unless your policy allows it, protect the api-keys file, and avoid using --base-url unless you fully trust and control the endpoint.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
script/audio2text_cli.py:111
Finding
Unrestricted Service Endpoint Allows API Key and Audio Disclosure## Vulnerability Details **File Location**: `script/audio2text_cli.py`, lines 111–115 and 160–202 **Vulnerability Type**: Unvalidated network destinations and sensitive-data exposure **Risk Level**: High ### Vulnerable Code ```python parser.add_argument( "--base-url", type=str, default=DEFAULT_BASE_URL, help=f"API 基础地址,默认 {DEFAULT_BASE_URL}", ) ``` ```python base = args.base_url.rstrip("/") headers = {"Authorization": f"Bearer {api_key}"} filename = path.name audio_format = get_format_from_path(args.audio_path) # 1) 获取 OpenClaw 上传凭证 token_url = f"{base}/tos/openclaw/upload-token?{urllib.parse.urlencode({'filename': filename})}" try: status, raw = _http_get(token_url, headers, timeout=30) except urllib.error.HTTPError as e: try: raw_err = e.read() body = json.loads(raw_err.decode("utf-8")) msg = body.get("message", raw_err.decode("utf-8", errors="replace")) except Exception: msg = str(e) print(f"获取上传凭证失败: {msg}", file=sys.stderr) sys.exit(1) except Exception as e: print(f"获取上传凭证失败: {e}", file=sys.stderr) sys.exit(1) data = _parse_json_response(status, raw, "获取上传凭证失败") payload = data.get("data", {}) signed_url = payload.get("signed_url") key = payload.get("key") if not signed_url or not key: print("响应缺少 signed_url 或 key", file=sys.stderr) sys.exit(1) # 2) 上传到 TOS try: with open(path, "rb") as f: body_bytes = f.read() put_status = _http_put(signed_url, body_bytes, timeout=120) ``` ### Technical Analysis The CLI allows callers to replace the intended Tinrec API endpoint with any value through `--base-url`. It does not enforce HTTPS, verify the destination hostname, restrict ports, or otherwise ensure that the endpoint belongs to Tinrec. The program then constructs an `Authorization: Bearer` header containing the user's Tinrec API key and sends it directly to the ...[truncated 2792 chars]
Remediation
## Remediation Suggestions 1. **Remove unrestricted endpoint overrides in production.** Use the fixed `https://api.tinrec.com/api` endpoint for normal operation. If endpoint replacement is needed for testing, place it behind an explicit development-only mode with prominent warnings. 2. **Validate the API destination before sending credentials.** - Require the `https` scheme. - Allowlist `api.tinrec.com`. - Reject embedded user information, fragments, unexpected ports, malformed hosts, and hostname suffix tricks. - Compare parsed hostnames rather than using substring or naive suffix checks. 3. **Validate the returned upload URL before opening the audio file.** - Require HTTPS. - Allowlist the documented Tinrec/TOS storage hostname or narrowly defined hostname set. - Reject unexpected ports, user-information components, and unapproved destinations. - Perform validation on the normalized parsed URL. 4. **Control redirects.** Reject redirects to origins outside the relevant allowlist. Ensure authorization headers are never forwarded to a different origin. 5. **Minimize credential exposure.** Prefer a permission-restricted key file or secret manager over `--api-key`, because command-line arguments may be visible through process inspection or shell history. Recommend restrictive key-file permissions, such as owner read/write only. 6. **Add explicit user disclosure.** Before upload, clearly identify the validated remote service receiving the recording, particularly when the file may contain confidential conversations. 7. **Add negative security tests.** Verify that the CLI rejects HTTP URLs, lookalike domains, embedded credentials, unapproved ports, attacker-controlled signed URLs, and redirects to untrusted origins.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill instructs use of network access, local file reads, and API key handling, but it does not declare any explicit tool scope or permission boundaries. This increases the chance an agent invokes the skill without clear consent or sandbox restrictions, especially since it processes local audio files and transmits them to a third-party cloud API.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill describes cloud transcription and summarization but does not warn that user audio and derived transcripts will be uploaded to an external service. In context, this is particularly sensitive because recordings may contain private conversations, meeting content, personal data, or regulated information, and users may not realize their local files leave the device.

External Transmission

Medium
Category
Data Exfiltration
Content
- `--api-keys-file`:API Key 文件路径(默认当前目录 `api-keys`),文件内第一行非空非注释即为 Key。
- `--api-key`:直接传入 Key,优先于文件和环境变量。
- `--base-url`:API 地址,默认 `https://api.tinrec.com/api`。
- `--json`:仅输出 JSON(含转写、总结、要点、发言人),便于 AI 解析。
- `--no-wait`:只提交不轮询,返回任务 id。
- `--poll-interval` / `--timeout`:轮询间隔与总超时。
Confidence
93% confidence
Finding
The skill is explicitly configured to send data to https://api.tinrec.com/api, which is a real external transmission of user-provided audio and potentially sensitive derived data. While this appears to be the intended function rather than malicious exfiltration, it is still security-relevant because local recordings are exported off-host to a third party.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The CLI reads a local audio file, uploads it to a remote storage endpoint via a signed URL, and submits it to a cloud transcription API, but it does not present an explicit user-facing privacy or data-transmission warning at runtime. Because audio recordings may contain sensitive personal, business, or regulated information, users may unknowingly exfiltrate confidential data to a third party service.

External Transmission

Medium
Category
Data Exfiltration
Content
import urllib.request
from pathlib import Path

DEFAULT_BASE_URL = "https://api.tinrec.com/api"
EXT_TO_FORMAT = {
    ".mp3": "mp3",
    ".wav": "wav",
Confidence
88% confidence
Finding
The skill is explicitly designed to send local audio content and API credentials to an external service at api.tinrec.com, and also uploads file bytes to a signed remote URL. In this context, external transmission is expected functionality, but it still carries real confidentiality risk because sensitive recordings leave the local environment and the destination can be changed with the user-controlled --base-url option.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
Natural-language policy violations include forcing a specific language without opt-in. The docstring, CLI description, help text, and status/error messages are all Chinese-only, with no indication that the tool is region-specific or that another language option is available.

Static analysis

No suspicious patterns detected.