Back to skill

Security audit

xeon_tts

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real local TTS and voice-cloning skill, but it exposes powerful unauthenticated services and enables persistent background services in ways users should review carefully.

Review before installing. Run it only on a trusted local machine or firewall port 9002, avoid exposing the Node gateway to a network, and consider changing the service to bind to 127.0.0.1. Do not use the direct clone-speak endpoint with arbitrary file paths, and prefer disabling autostart until you have reviewed the systemd units and dependency sources.

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 (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.js:676
Finding
<![CDATA[Unauthenticated TTS Gateway Exposed on All Network Interfaces]]><![CDATA[ ## Vulnerability Details **File Location**: `server.js:676-814` **Vulnerability Type**: Missing authentication and authorization on a network-exposed service **Risk Level**: High ### Vulnerable Code ```js const server = http.createServer(async (req, res) => { try { if (req.method === 'GET' && req.url === '/health') { return sendJson(res, 200, { status: 'ok', port: config.port }); } if (req.method === 'GET' && req.url.startsWith('/api/session/state')) { const url = new URL(req.url, 'http://127.0.0.1'); const sessionId = url.searchParams.get('sessionId') || config.openclawSession; const userId = url.searchParams.get('userId') || 'anonymous'; const current = getSessionState(sessionId, userId).session; return sendJson(res, 200, { success: true, session: current }); } if (req.method === 'POST' && req.url === '/api/workflow/message') { const body = await readJsonBody(req); const result = await handleWorkflowMessage(body || {}); return sendJson(res, 200, result); } if (req.method === 'POST' && req.url === '/api/tts/custom-speak') { const body = await readJsonBody(req); const result = await synthesizeCustomVoice({ text: body.text, style: body.style || '普通', language: body.language || config.defaultLanguage, speakerId: body.speakerId || config.defaultSpeaker, }); return sendJson(res, 200, { success: true, ...result }); } if (req.method === 'POST' && req.url === '/api/tts/clone-speak') { const body = await readJsonBody(req); const result = await synthesizeClonedVoice({ text: body.text, referenceAudioPath: body.referenceAudioPath, language: body.language || config.defaultLanguage, referenceText: body.referenceText || '', }); return sendJson(res, 200, { success: true, ...result }); } return sendJson(res, 404, { success: false, error: 'not found' }) ...[truncated 2489 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind the gateway to loopback by default: ```js server.listen(config.port, '127.0.0.1', () => { // ... }); ``` 2. If remote access is required, require an unpredictable bearer token or mutually authenticated TLS before processing any `/api/*` route. 3. Authorize session access using trusted identity supplied by the authenticated OpenClaw integration; do not treat caller-selected `userId` or `sessionId` values as proof of identity. 4. Restrict port 9002 using host firewall rules and network access-control lists. 5. Put remote deployments behind a TLS-enabled reverse proxy. 6. Add request-rate, inference-concurrency, and per-user quota controls. 7. Return only necessary session fields and avoid disclosing absolute filesystem paths. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
server.js:527
Finding
<![CDATA[Arbitrary Local File Read Through referenceAudioPath]]><![CDATA[ ## Vulnerability Details **File Location**: `server.js:527-550, 795-805` **Vulnerability Type**: User-controlled filesystem path used in a privileged file read **Risk Level**: High ### Vulnerable Code ```js async function synthesizeClonedVoice(options) { const text = String(options.text || '').trim(); if (!text) { throw new Error('缺少要生成的文本'); } if (!options.referenceAudioPath || !fs.existsSync(options.referenceAudioPath)) { throw new Error('当前会话没有可用的参考音频,请先上传 3 到 5 秒参考音频'); } const timing = validateRequestedOutput(text, Number(config.maxCloneOutputSeconds || 20), '音色克隆'); const form = new FormData(); form.append('text', text); form.append('model', config.cloneModel); form.append('tts_model', config.cloneModel); form.append('tts_mode', config.cloneMode); form.append('language', options.language || config.defaultLanguage); form.append('x_vector_only_mode', String(config.cloneMode === 'voice_clone_xvector')); const audioBuffer = fs.readFileSync(options.referenceAudioPath); form.append( 'prompt_audio', new Blob([audioBuffer], { type: getMimeType(options.referenceAudioPath) }), path.basename(options.referenceAudioPath), ); ``` The path is obtained directly from the request body: ```js if (req.method === 'POST' && req.url === '/api/tts/clone-speak') { const body = await readJsonBody(req); const result = await synthesizeClonedVoice({ text: body.text, referenceAudioPath: body.referenceAudioPath, language: body.language || config.defaultLanguage, referenceText: body.referenceText || '', }); return sendJson(res, 200, { success: true, ...result }); } ``` ### Technical Analysis The `/api/tts/clone-speak` endpoint accepts `referenceAudioPath` directly from an API caller. The only filesystem validation is an existence check. The path is not canonicalized, restricted to `config.referencesDir`, associated with an authenticated session, or resolved from trusted server-side state. Conse ...[truncated 1848 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `referenceAudioPath` from the public API contract. 2. Return an opaque, unpredictable reference ID after an authenticated upload and resolve that ID through trusted server-side session state. 3. Canonicalize and validate every resolved path before reading it: ```js const root = fs.realpathSync(config.referencesDir); const candidate = fs.realpathSync(serverResolvedPath); if (candidate !== root && !candidate.startsWith(`${root}${path.sep}`)) { throw new Error('Invalid reference audio path'); } ``` 4. Reject symbolic links or verify the opened file descriptor remains within the managed directory to reduce time-of-check/time-of-use risk. 5. Require a regular file and enforce a small maximum size before reading. 6. Associate each reference ID with an authenticated user and session. 7. Keep `flaskTtsUrl` restricted to an allowlisted loopback endpoint unless remote forwarding is explicitly secured. 8. Run the service under a dedicated account with access only to its model, runtime, reference, and output directories. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
server.js:265
Finding
<![CDATA[Unbounded Request Bodies and Insufficient Resource-Abuse Controls]]><![CDATA[ ## Vulnerability Details **File Location**: `server.js:265-279, 567-579` **Vulnerability Type**: Unbounded request buffering and unrestricted multipart uploads **Risk Level**: Medium ### Vulnerable Code ```js function readJsonBody(req) { return new Promise((resolve, reject) => { const chunks = []; req.on('data', (chunk) => chunks.push(chunk)); req.on('end', () => { try { const text = Buffer.concat(chunks).toString('utf8'); resolve(text ? JSON.parse(text) : {}); } catch (error) { reject(error); } }); req.on('error', reject); }); } ``` ```js function parseMultipart(req) { const form = new formidable.IncomingForm({ uploadDir: config.runtimeDir, keepExtensions: true, multiples: false, }); return new Promise((resolve, reject) => { form.parse(req, (error, fields, files) => { if (error) { reject(error); return; } resolve({ fields, files }); }); }); } ``` ### Technical Analysis JSON requests are accumulated into an unrestricted array and concatenated only after the client finishes sending data. There is no byte counter, `Content-Length` validation, request timeout, or early termination after a configured threshold. The multipart parser is constructed without an explicit conservative `maxFileSize`, `maxTotalFileSize`, or field-size policy appropriate for the expected three-to-five-second reference clips. Uploaded data is written into `config.runtimeDir`. The application also lacks authentication, rate limiting, per-client quotas, and inference-concurrency controls. Text-duration validation limits estimated audio duration, but it does not prevent attackers from repeatedly submitting valid-size requests or oversized transport bodies. ### Attack Path 1. An attacker connects to port 9002. 2. For memory exhaustion, the attacker sends a very large or indefinitely streamed JSON body to a JSON endpoint. 3. The server retains each rec ...[truncated 903 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement streaming size enforcement for JSON bodies and destroy the request after a small configured threshold: ```js const MAX_JSON_BYTES = 64 * 1024; let received = 0; req.on('data', (chunk) => { received += chunk.length; if (received > MAX_JSON_BYTES) { req.destroy(new Error('Request body too large')); return; } chunks.push(chunk); }); ``` 2. Configure Formidable with limits suitable for short audio clips: ```js const form = new formidable.IncomingForm({ uploadDir: config.runtimeDir, keepExtensions: true, multiples: false, maxFiles: 1, maxFileSize: 10 * 1024 * 1024, maxTotalFileSize: 10 * 1024 * 1024, maxFields: 10, maxFieldsSize: 64 * 1024, }); ``` 3. Set HTTP header, request, and idle timeouts. 4. Authenticate callers and enforce per-user and per-IP rate limits. 5. Limit concurrent inference jobs and queue depth. 6. Check available disk space and apply per-user storage quotas. 7. Ensure temporary files are removed in `finally` blocks on every success and failure path. 8. Apply systemd memory, CPU, process, and filesystem quotas as defense in depth. ]]>

T08 · Insecure Dependencies

Warning
Location
setup_env.sh:110
Finding
<![CDATA[Executable Dependencies and Installer Downloaded Without Immutable Pinning or Integrity Verification]]><![CDATA[ ## Vulnerability Details **File Location**: `setup_env.sh:110-139, 201-205, 231-238`; `install.sh:30-36` **Vulnerability Type**: Unsafe software supply-chain installation **Risk Level**: Medium ### Vulnerable Code The downloaded Miniconda installer is executed without checksum or signature verification: ```bash setup_miniconda() { log_step "准备 Miniconda Python 3.10" local conda_dir="$HOME/miniconda3" local conda_url="https://repo.anaconda.com/miniconda/Miniconda3-py310_23.11.0-2-Linux-x86_64.sh" if [[ "$FORCE" -eq 1 && -d "$conda_dir" ]]; then rm -rf "$conda_dir" fi if [[ ! -d "$conda_dir" ]]; then wget --timeout=120 -q "$conda_url" -O /tmp/miniconda.sh || curl -fsSL --connect-timeout 120 "$conda_url" -o /tmp/miniconda.sh bash /tmp/miniconda.sh -b -p "$conda_dir" >/dev/null 2>&1 rm -f /tmp/miniconda.sh fi PYTHON_CMD="$conda_dir/bin/python" [[ -x "$PYTHON_CMD" ]] || { log_error "Miniconda 安装失败"; exit 1; } log_info "Python 就绪: $($PYTHON_CMD --version 2>&1)" } ``` Python dependencies use mutable, unpinned package specifications: ```bash setup_venv() { if [[ "$FORCE" -eq 1 && -d venv ]]; then rm -rf venv fi if [[ ! -d venv ]]; then log_step "创建虚拟环境" "$PYTHON_CMD" -m venv venv fi source venv/bin/activate pip install -q --upgrade pip } install_python_packages() { log_step "安装 Python TTS 服务包" if ! pip install -q --upgrade "$TTS_PIP_SPEC"; then log_error "安装失败: $TTS_PIP_SPEC" log_error "如果包尚未发布,请设置 XDP_TTS_PIP_SPEC=/path/to/xdp_tts_service.whl 后重试" exit 1 fi log_info "已安装: $TTS_PIP_SPEC" } ``` The default package specification is not version-pinned: ```bash TTS_PIP_SPEC="${XDP_TTS_PIP_SPEC:-xdp-tts-service}" ``` The Hugging Face client and model repositories are likewise not pinned to immutable versions or revisions: ```bash if pip install -q 'huggingface_hub[cli]' >/dev/null 2>&1 || pip install -q huggingface_hub >/dev/null 2>&1; then ``` ```bash if [[ "$(basename "$hf ...[truncated 2736 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Publish and verify an expected SHA-256 digest or vendor signature for the Miniconda installer before execution. 2. Download to a uniquely created private temporary directory rather than the fixed `/tmp/miniconda.sh` path. 3. Pin Python packages to reviewed exact versions. 4. Maintain a lock file containing hashes and install with a command equivalent to: ```bash pip install --require-hashes -r requirements.lock ``` 5. Avoid unconditional `--upgrade` during normal installation. 6. Pin `huggingface_hub` and all transitive Python dependencies. 7. Pin model downloads to reviewed immutable commit revisions using the Hugging Face CLI revision option. 8. Validate downloaded model artifact manifests and hashes before loading them. 9. Use `npm ci` with the committed `package-lock.json` instead of `npm install`. 10. Add automated dependency vulnerability and provenance scanning to release validation. 11. Document all external executable sources, expected versions, revisions, and integrity hashes. ]]>
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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (42)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
if [[ ! -d "$conda_dir" ]]; then
    wget --timeout=120 -q "$conda_url" -O /tmp/miniconda.sh || curl -fsSL --connect-timeout 120 "$conda_url" -o /tmp/miniconda.sh
    bash /tmp/miniconda.sh -b -p "$conda_dir" >/dev/null 2>&1
    rm -f /tmp/miniconda.sh
  fi
  PYTHON_CMD="$conda_dir/bin/python"
  [[ -x "$PYTHON_CMD" ]] || { log_error "Miniconda 安装失败"; exit 1; }
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Vague Triggers

Medium
Confidence
81% confidence
Finding
README 将“我要克隆音色”“帮我克隆我的声音”作为触发示例,但没有说明完整触发词范围、必须包含哪些意图信号,或哪些相似日常表达不应触发该流程。对于 markdown 技能说明,这种缺少约束的自然语言触发描述可能导致在 QQBOT 中被过宽匹配而误进入音色克隆工作流。

Vague Triggers

Medium
Confidence
78% confidence
Finding
“用开心的语气朗读:…”和“生成语音:…”被作为用户说法示例,但文档未说明是否只有这些固定短语会触发,还是任意包含类似措辞的消息都可能命中。由于缺少负例或上下文限制,这类描述对 markdown 文件而言属于触发条件不够具体。

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
README 中的配置示例将 `defaultLanguage` 固定为 `Chinese`,同时文件整体未说明用户是否可以选择其他语言或是否仅适用于特定中文场景。按规则,未提供用户语言/locale 选择或明确的合理地域限制,属于自然语言层面的语言策略风险。

External Transmission

Medium
Category
Data Exfiltration
Content
bash stop_tts.sh
bash self_check.sh

curl http://127.0.0.1:5002/api/health
curl http://127.0.0.1:9002/health
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The file’s operational instructions and user-facing guidance are entirely in Chinese, and there is no indication that users may choose another language or that the skill is intentionally limited to a Chinese-speaking deployment. Under the policy, forcing a specific language without opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
This manifest sets `defaultLanguage` to `Chinese`, which is a natural-language locale choice applied by default. Under the policy, forcing a specific language without offering user choice or documenting a justified region-specific constraint is a policy violation.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The installer modifies the host by installing systemd services and then starts local services automatically, but there is no visible consent prompt, dry-run mode, or explanation of exactly what services will be registered. In a skill package with no trusted metadata or stated purpose context, persistent service installation increases risk because it creates background execution and boot persistence on the user's machine.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script installs startup services and may immediately launch them without any explicit warning that it will change system boot behavior. This is dangerous because users may unknowingly grant persistence to software, making rollback harder and increasing the blast radius if any subordinate script or service is unsafe.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This shell script creates persistent user-level systemd service files and later enables them to start immediately and on login, which changes the user's system configuration. While there is a final success message, there is no warning, confirmation prompt, or explanatory comment/docstring before these file writes and service-enablement actions occur.

Session Persistence

Medium
Category
Rogue Agent
Content
EOF

systemctl --user daemon-reload
systemctl --user enable --now "$TTS_UNIT_NAME"
systemctl --user enable --now "$NODE_UNIT_NAME"
echo "xeontts 开机自启已启用"
Confidence
84% confidence
Finding
This command enables and starts a per-user systemd service, causing the TTS component to persist across future user sessions. Persistence is security-relevant because any compromised or vulnerable service installed this way will automatically restart and remain available without further user action.

Session Persistence

Medium
Category
Rogue Agent
Content
systemctl --user daemon-reload
systemctl --user enable --now "$TTS_UNIT_NAME"
systemctl --user enable --now "$NODE_UNIT_NAME"
echo "xeontts 开机自启已启用"
Confidence
84% confidence
Finding
This command enables and starts the Node gateway as a persistent per-user service. In skill context, this is more sensitive because it exposes a long-running gateway process via autostart; if the server code later has weaknesses or binds too broadly, persistence increases exposure and makes removal less obvious to users.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This shell script emits multiple user-facing messages such as 健康检查通过, 检查本地服务, and 自检通过 entirely in Chinese. Under the policy, forcing a specific language without user opt-in or a documented regional justification is a natural-language policy violation.

Session Persistence

Medium
Category
Rogue Agent
Content
fi

log_step "检查 systemd 状态"
if systemctl --user is-enabled xeontts-tts.service >/dev/null 2>&1; then pass "xeontts-tts.service 已启用"; else fail "xeontts-tts.service 未启用"; fi
if systemctl --user is-enabled xeontts-node.service >/dev/null 2>&1; then pass "xeontts-node.service 已启用"; else fail "xeontts-node.service 未启用"; fi

if [[ "$FAIL_COUNT" -gt 0 ]]; then
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
fi

log_step "检查 systemd 状态"
if systemctl --user is-enabled xeontts-tts.service >/dev/null 2>&1; then pass "xeontts-tts.service 已启用"; else fail "xeontts-tts.service 未启用"; fi
if systemctl --user is-enabled xeontts-node.service >/dev/null 2>&1; then pass "xeontts-node.service 已启用"; else fail "xeontts-node.service 未启用"; fi

if [[ "$FAIL_COUNT" -gt 0 ]]; then
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The configuration sets `defaultLanguage` to `Chinese`, and later request handlers fall back to this value when no language is supplied. This creates a language/locale policy issue because the skill defaults users into a specific language rather than offering a neutral default or explicit opt-in.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
check_sudo() {
  if [[ "$EUID" -eq 0 ]]; then
    SUDO=""
  elif command -v sudo >/dev/null 2>&1; then
    SUDO="sudo"
  else
    SUDO=""
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
check_sudo() {
  if [[ "$EUID" -eq 0 ]]; then
    SUDO=""
  elif command -v sudo >/dev/null 2>&1; then
    SUDO="sudo"
  else
    SUDO=""
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
case "$os_id" in
    ubuntu|debian)
      log_step "安装系统依赖 (Debian/Ubuntu)"
      $SUDO apt-get update -qq >/dev/null 2>&1 || true
      $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg >/dev/null 2>&1 || \
        $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg
      ;;
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
case "$os_id" in
    ubuntu|debian)
      log_step "安装系统依赖 (Debian/Ubuntu)"
      $SUDO apt-get update -qq >/dev/null 2>&1 || true
      $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg >/dev/null 2>&1 || \
        $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg
      ;;
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
case "$os_id" in
    ubuntu|debian)
      log_step "安装系统依赖 (Debian/Ubuntu)"
      $SUDO apt-get update -qq >/dev/null 2>&1 || true
      $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg >/dev/null 2>&1 || \
        $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg
      ;;
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
case "$os_id" in
    ubuntu|debian)
      log_step "安装系统依赖 (Debian/Ubuntu)"
      $SUDO apt-get update -qq >/dev/null 2>&1 || true
      $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg >/dev/null 2>&1 || \
        $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg
      ;;
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
case "$os_id" in
    ubuntu|debian)
      log_step "安装系统依赖 (Debian/Ubuntu)"
      $SUDO apt-get update -qq >/dev/null 2>&1 || true
      $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg >/dev/null 2>&1 || \
        $SUDO apt-get install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg
      ;;
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

External Transmission

Medium
Category
Data Exfiltration
Content
local pkg_mgr="yum"
      command -v dnf >/dev/null 2>&1 && pkg_mgr="dnf"
      $SUDO "$pkg_mgr" install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg which >/dev/null 2>&1 || \
        $SUDO "$pkg_mgr" install -y wget curl git lsof net-tools unzip bzip2 ca-certificates ffmpeg which
      ;;
    *)
      log_warn "未知系统,跳过系统依赖自动安装"
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
When --force is used, the script unconditionally removes the entire $HOME/miniconda3 directory with rm -rf. Although the script has general logging, there is no explicit warning at the point of deletion, no confirmation prompt, and no comment/docstring disclosing that an existing Python environment will be destroyed.

Static analysis

Detected: suspicious.dynamic_code_execution, suspicious.install_untrusted_source, suspicious.potential_exfiltration

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
self_check.sh:41

Install source points to URL shortener or raw IP.

Warn
Code
suspicious.install_untrusted_source
Location
.clawhub.json:13

Install source points to URL shortener or raw IP.

Warn
Code
suspicious.install_untrusted_source
Location
config.example.json:3

Sensitive-looking file read is paired with a network send.

Warn
Code
suspicious.potential_exfiltration
Location
server.js:149