Back to skill

Security audit

NapCat QQ Bridge Installer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real QQ bridge installer, but it exposes unauthenticated local/network services that can read logs/configuration and send QQ messages.

Review carefully before installing. This skill should only be used on a controlled Windows machine, preferably isolated from untrusted networks, and only after you are comfortable with it installing software, starting services, storing QQ chat logs, invoking OpenClaw from QQ messages, and exposing management/message-sending endpoints unless the artifact is hardened first.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (7)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
assets/runtime/bridge.mjs:469
Finding
Unauthenticated Bridge Management API Exposes Secrets, Logs, Configuration, and Message-Sending Capabilities<![CDATA[ ## Vulnerability Details **File Location**: `assets/runtime/bridge.mjs:469-513` **Vulnerability Type**: Missing authentication and authorization on a network-accessible management API **Risk Level**: Critical ### Vulnerable Code ```javascript app.get('/logs', (_req, res) => { try { res.json(readdirSync(LOG_DIR).filter(name => name.endsWith('.log')).sort()); } catch { res.json([]); } }); app.get('/logs/:filename', (req, res) => { const path = resolve(LOG_DIR, req.params.filename); if (!existsSync(path)) { res.status(404).send('not found'); return; } res.type('text/plain; charset=utf-8').send(readFileSync(path, 'utf-8')); }); app.get('/config', (_req, res) => { res.json(config); }); app.post('/config', (req, res) => { config = deepMerge(config, req.body || {}); saveConfig(config); res.json({ ok: true, config }); }); app.post('/send_qq', async (req, res) => { const { type, target, message } = req.body || {}; if (!type || !target || !message) { res.status(400).json({ error: 'need type, target, message' }); return; } try { const data = await sendQQMessage(type, target, message, true); res.json({ ok: true, data }); } catch (error) { res.status(502).json({ ok: false, error: error.message }); } }); app.listen(Number(config.bridge.httpPort || 3002), () => { console.log(`[bridge] HTTP listening on ${config.bridge.httpPort || 3002}`); }); ``` ### Technical Analysis The Express application does not authenticate or authorize any management endpoint. Because `app.listen()` does not specify a loopback address, Node.js ordinarily listens on all available interfaces. The exposed endpoints provide security-sensitive capabilities: - `/logs` and `/logs/:filename` disclose stored QQ conversations. - `/config` returns the complete runtime configuration, including the NapCat API bearer token and QQ identifiers. - `POST /config` permits arbitrary configuration changes. - `POST /send_qq` sends ...[truncated 1208 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind the API explicitly to loopback: ```javascript app.listen(port, '127.0.0.1', callback); ``` 2. Require a separately generated, high-entropy bearer token on every endpoint. 3. Remove `/config`, `/logs`, and `/send_qq` unless operationally necessary. 4. Return a redacted configuration that never includes API tokens. 5. Apply role-based authorization so read-only health checks cannot send messages or alter settings. 6. Validate log filenames against a strict allowlist such as `^[A-Za-z0-9._-]+\.log$`. 7. Resolve the requested file and verify that it remains beneath `resolve(LOG_DIR)` before reading it. 8. Add host firewall rules restricting the bridge port to the local machine. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
assets/runtime/bridge.mjs:200
Finding
Unauthenticated Configuration Changes Can Redirect and Exfiltrate the NapCat Bearer Token<![CDATA[ ## Vulnerability Details **File Location**: `assets/runtime/bridge.mjs:200-223, 302-315, 490-493` **Vulnerability Type**: Credential exfiltration through attacker-controlled service endpoints **Risk Level**: Critical ### Vulnerable Code ```javascript async function getNapCatStatus() { const response = await fetch(`${config.napcat.apiUrl}/get_status`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${config.napcat.apiToken}`, }, signal: AbortSignal.timeout(3000), }); const data = await response.json().catch(() => ({})); if (!response.ok) throw new Error(`NapCat ${response.status}`); return data; } ``` ```javascript const response = await fetch(`${config.napcat.apiUrl}/${apiPath}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${config.napcat.apiToken}`, }, body: JSON.stringify(body), }); ``` ```javascript app.post('/config', (req, res) => { config = deepMerge(config, req.body || {}); saveConfig(config); res.json({ ok: true, config }); }); ``` ### Technical Analysis The unauthenticated configuration endpoint accepts arbitrary nested values and persistently merges them into the active configuration. An attacker can replace `napcat.apiUrl` with an external URL under their control. Status, typing-indicator, and message-sending operations subsequently attach the real NapCat token to requests through the `Authorization: Bearer` header. No origin allowlist or loopback validation prevents the token from being sent to a remote host. Normal communication with a local NapCat API is necessary for the declared functionality. Permitting an unauthenticated caller to redirect token-bearing requests is not necessary and violates least privilege. ### Attack Path 1. The attacker sends an unauthenticated request to `POST /config`. 2. The request sets `napcat.apiUrl` to an attacker-controlled HTTP or HTTPS endpoint. 3. T ...[truncated 684 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove runtime modification of `napcat.apiUrl`, `wsUrl`, and authentication tokens from the HTTP API. 2. If endpoint changes are required, accept only loopback addresses and explicitly reject user information, redirects, and nonlocal resolved IP addresses. 3. Authenticate and authorize all configuration changes. 4. Store secrets separately from remotely mutable configuration. 5. Do not return secrets in configuration responses. 6. Disable automatic redirect following for token-bearing requests or validate every redirect target. 7. Restart with a validated configuration rather than immediately activating arbitrary request bodies. 8. Rotate the NapCat token after fixing any exposed installation. ]]>

T01 · Skill Instruction Hijacking

Error
Location
assets/runtime/bridge.mjs:235
Finding
Untrusted QQ Content Is Passed Directly to a Potentially Tool-Capable OpenClaw Agent<![CDATA[ ## Vulnerability Details **File Location**: `assets/runtime/bridge.mjs:235-269, 340-406` **Vulnerability Type**: Indirect prompt injection and missing caller authorization **Risk Level**: High ### Vulnerable Code ```javascript function buildDirectReplyPrompt({ event, sender, richText, contextBlock }) { let prefix = `[QQ ${event.message_type}]`; if (event.group_id) prefix += ` [group ${event.group_id}]`; return `${prefix} ${sender}: ${richText} ${contextBlock} Reply with exactly the plain text that should be sent back to QQ. Voice target: - Sound ${config.persona.tone}. - Keep it human and believable in QQ chat. - Replies should usually be 1-2 short sentences. Rules: - Reply in the same language as the user unless context strongly suggests otherwise. - Do not use markdown, code fences, or surrounding quotes. - Do not describe actions, tools, or internal reasoning. - Do not use parentheses, brackets, stage directions, or side comments for tone. - Avoid excessive ellipses or exaggerated catchphrases. - ${config.persona.extraRules} - If the user only mentioned the bot without a real request, ask a short follow-up.`; } async function getOpenClawDirectReply(sessionId, prompt) { const timeoutSeconds = Number(config.openClaw.timeoutSeconds || 120); const args = [ '-d', config.openClaw.wslDistro, '--', 'docker', 'exec', config.openClaw.container, 'openclaw', 'agent', '--session-id', sessionId, '--message', prompt, '--json', '--timeout', String(timeoutSeconds), ]; const { stdout, stderr } = await execFileAsync('wsl', args, { windowsHide: true, timeout: (timeoutSeconds + 15) * 1000, maxBuffer: 10 * 1024 * 1024, }); ``` ```javascript const isAtBot = Array.isArray(event.message) && event.message.some(seg => seg.type === 'at' && String(seg.data?.qq) === String(selfId)); const isPrivate = !event.group_id; if (!isPrivate && !isAtBot) return; const recentCtx = getRecentContext(key); const contex ...[truncated 2041 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict agent invocation to explicit QQ user and group allowlists. 2. Use `adminQq` for authorization where administrative interaction is intended. 3. Run chat replies through a dedicated agent profile with tools, shell execution, filesystem access, secrets, and memory writes disabled. 4. Place behavioral rules in a trusted system or developer instruction rather than concatenating them with user text. 5. Pass QQ messages as clearly delimited structured data and instruct the agent that the data is untrusted. 6. Detect and reject requests concerning system prompts, credentials, files, commands, tools, or policy changes. 7. Limit session lifetime and avoid retaining adversarial context indefinitely. 8. Apply output validation before returning generated text to QQ. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/manage.py:407
Finding
Generated OneBot Services Listen on All Interfaces Without Authentication<![CDATA[ ## Vulnerability Details **File Location**: `scripts/manage.py:407-438` **Vulnerability Type**: Insecure network binding and missing OneBot authentication **Risk Level**: Critical ### Vulnerable Code ```python "httpServers": [ { "name": "OpenClawApi", "enable": True, "host": "0.0.0.0", "port": settings["napcat_api_port"], "enableCors": True, "enableWebsocket": False, "messagePostFormat": "array", "token": settings["api_token"], "debug": True, } ], "httpSseServers": [], "httpClients": [ { "name": "OpenClawBridge", "enable": True, "url": f"http://127.0.0.1:{settings['bridge_port']}/", "messagePostFormat": "array", "reportSelfMessage": False, "token": "", "debug": True, } ], "websocketServers": [ { "name": "OpenClawBridge", "enable": True, "host": "0.0.0.0", "port": settings["napcat_ws_port"], "token": "", } ], ``` ### Technical Analysis The generated OneBot WebSocket server binds to `0.0.0.0` and has an empty authentication token. The bridge operates on the same host, so exposing this service to other network interfaces is unnecessary. The HTTP API also binds to all interfaces. Although it receives a generated token, enabling CORS and debug mode enlarges the attack surface. The outbound HTTP client to the bridge has an empty token, matching the bridge's lack of authentication. ### Attack Path 1. An attacker scans the host for the configured NapCat HTTP and WebSocket ports, normally 3001 and 6700. 2. The attacker connects directly to the unauthenticated WebSocket service. 3. Depending on NapCat's OneBot implementation, the attacker receives QQ events or invokes available API operations. 4. The attacker uses exposed account context to monitor conversations or act through the QQ session. 5. If the HTTP token is separately disclosed through the bridge API, the at ...[truncated 310 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind every same-host OneBot service to `127.0.0.1`. 2. Generate independent high-entropy tokens for HTTP, WebSocket, and bridge communication. 3. Never generate a WebSocket server with an empty token. 4. Disable CORS unless browser-based cross-origin access is explicitly required. 5. Disable debug mode in production-generated configurations. 6. Disable unused listeners and prefer a single authenticated transport. 7. Add Windows Firewall rules that reject inbound connections to these ports from non-loopback interfaces. 8. Rotate tokens and regenerate configurations for existing installations. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
assets/runtime/bridge.mjs:117
Finding
QQ Conversations Are Persistently Logged in Plaintext and Exposed Beyond Bot-Directed Messages<![CDATA[ ## Vulnerability Details **File Location**: `assets/runtime/bridge.mjs:117-149, 355-361` **Vulnerability Type**: Excessive collection and insecure storage of sensitive chat data **Risk Level**: High ### Vulnerable Code ```javascript function shouldMonitorGroup(groupId) { const groups = config.monitoredGroups || []; if (groups.length === 0) return true; return groups.includes(Number(groupId)); } ``` ```javascript function logFileForEvent(event) { if (event.group_id) return `${LOG_DIR}/${today()}-g${event.group_id}.log`; return `${LOG_DIR}/${today()}-p${event.user_id}.log`; } function logMessage(event, sender, text) { appendFileSync(logFileForEvent(event), `[${nowStr()}] ${sender}: ${text}\n`, 'utf-8'); } ``` ```javascript if (event.group_id && shouldMonitorGroup(event.group_id)) { logMessage(event, sender, text); } if (!event.group_id) { logMessage(event, sender, text); } ``` ### Technical Analysis All private messages are written to plaintext log files. When `monitoredGroups` is empty, the code treats every group as monitored and logs all group messages, including messages that do not mention or address the bot. The files contain sender names, account-related identifiers in filenames, timestamps, and message content. No retention limit, encryption, redaction, consent mechanism, or restrictive permission setup is implemented. The separate unauthenticated `/logs` routes make the stored data remotely retrievable. Collecting all group traffic is broader than the declared requirement to respond to bot-directed messages and therefore exceeds minimum necessary data access. ### Attack Path 1. The bridge joins or observes QQ groups through the bot account. 2. With an empty group list, it records all messages from every visible group. 3. It also records every incoming private message. 4. Logs accumulate indefinitely in the `chat-logs` directory. 5. A local user, malware, backup recipient, or remote caller of the unauthenticated log API ...[truncated 315 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Default to monitoring no groups rather than all groups. 2. Log only messages explicitly directed to the bot and only when logging is affirmatively enabled. 3. Disable message-body logging by default; use minimal operational metadata where possible. 4. Redact QQ identifiers, tokens, URLs, and other sensitive values. 5. Enforce a short retention period with automatic deletion or rotation. 6. Apply restrictive filesystem permissions to the log directory. 7. Encrypt logs at rest if message retention is genuinely required. 8. Remove HTTP log retrieval or protect it with strong authentication and authorization. 9. Clearly notify the operator about data collection and obtain appropriate participant consent. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/manage.py:220
Finding
Mutable External Executables and Packages Are Downloaded and Executed Without Integrity Verification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/manage.py:220-236, 253-267` **Vulnerability Type**: Unpinned remote payload retrieval and unsafe software supply chain **Risk Level**: High ### Vulnerable Code ```python def install_napcat_runtime(root: Path, asset_name: str | None, force: bool) -> dict: napcat_home = root / "napcat" release = fetch_release_payload(DEFAULT_NAPCAT_RELEASE_API) asset = choose_napcat_asset(release, asset_name) with tempfile.TemporaryDirectory(prefix="napcat-skill-") as temp_dir: temp_root = Path(temp_dir) archive_path = temp_root / asset["name"] extract_root = temp_root / "extract" print(f"Downloading {asset['name']} from {asset['browser_download_url']}") download_file(asset["browser_download_url"], archive_path) with zipfile.ZipFile(archive_path) as zip_handle: zip_handle.extractall(extract_root) runtime_root = locate_runtime_root(extract_root) if force and napcat_home.exists(): for stale in ("bridge.mjs",): candidate = napcat_home / stale if candidate.exists(): candidate.unlink() copy_tree(runtime_root, napcat_home) ``` ```python def ensure_openclaw_container(distro: str, container_name: str, openclaw_port: int) -> None: quoted = shlex.quote(container_name) names = run_wsl(distro, "docker ps -a --format '{{.Names}}'", check=False).stdout.splitlines() if container_name not in {name.strip() for name in names}: run_wsl(distro, f"docker pull {shlex.quote(DEFAULT_CONTAINER_IMAGE)}") create_cmd = ( "docker create " f"--name {quoted} " f"-p {openclaw_port}:18789 " "-v openclaw-home:/root/.openclaw " "-w /root " f"{shlex.quote(DEFAULT_CONTAINER_IMAGE)} sleep infinity" ) run_wsl(distro, create_cmd) run_wsl(distro, f"docker start {quoted} >/dev/n ...[truncated 2018 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin exact NapCat and OpenClaw versions reviewed by the Skill publisher. 2. Publish and verify SHA-256 or stronger hashes before extraction or installation. 3. Verify Authenticode or other publisher signatures for Windows binaries where available. 4. Pin the container image by immutable digest. 5. Use an npm lockfile or install an exact package version rather than the latest global package. 6. Require explicit user confirmation before downloading or upgrading executable components. 7. Stage extracted files and scan them before execution. 8. Reject archives containing absolute paths, parent-directory traversal entries, links, or unexpected executable files. 9. Document a controlled update process rather than resolving the latest release automatically. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
assets/runtime/start-all.bat.txt:1
Finding
Entire Runtime Is Launched with Administrator Privileges and Stop Script Terminates Unrelated QQ Processes<![CDATA[ ## Vulnerability Details **File Location**: `assets/runtime/start-all.bat.txt:1-8`; `assets/runtime/stop-all.bat.txt:20-23` **Vulnerability Type**: Excessive privilege and overbroad process termination **Risk Level**: High ### Vulnerable Code ```bat @echo off chcp 65001 >nul net session >nul 2>&1 if %ERRORLEVEL% neq 0 ( echo Administrator rights are required. Relaunching... powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs" exit /b ) ``` ```bat echo [2/3] Stopping NapCat / QQ... taskkill /im QQ.exe /f >nul 2>&1 echo QQ stopped ``` ### Technical Analysis The start script requires elevation before starting the OpenClaw container, Node bridge, downloaded NapCat components, and QQ injection process. The script does not isolate a specific privileged operation; consequently, mutable third-party components are launched from an administrator context. The stop script force-terminates every process named `QQ.exe`, rather than tracking and stopping only the QQ instance created for the bridge. This can terminate unrelated user sessions and cause unsaved state or data loss. The declared local bridge functionality does not establish that the Node bridge, health checks, Docker commands, or all NapCat runtime operations require administrator privileges. ### Attack Path 1. The user starts the generated launcher and accepts the User Account Control elevation prompt. 2. The batch process runs with administrator privileges. 3. The launcher starts downloaded NapCat code and associated runtime components from that elevated context. 4. If any component or runtime file has been compromised, its payload executes with elevated host privileges. 5. When stopping the bridge, the stop script force-kills all `QQ.exe` processes, including unrelated instances. ### Impact Assessment A compromised Windows-side component may receive administrator-level privileges, substantially increasing its ability to alter files, processes, services, a ...[truncated 116 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Run the Node bridge, WSL commands, container, and QQ client as the ordinary user. 2. Identify the exact operation requiring elevation and move only that operation into a narrowly scoped helper. 3. Do not launch downloaded or mutable third-party runtime code from an elevated parent process. 4. Record the process ID of the QQ instance started by the bridge. 5. Stop only the recorded process after verifying its executable path and creation context. 6. Avoid `/f` unless graceful shutdown has failed after a defined timeout. 7. Warn the user before terminating a process and preserve unrelated QQ sessions. 8. Document any unavoidable elevated operation and explain why it 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (21)

Ae1

High
Category
analysis-evasion
Content
- overlay a local `bridge.mjs`, `start-all.bat`, and `stop-all.bat`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- overlay a local `bridge.mjs`, `start-all.bat`, and `stop-all.bat`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The file exposes a persistent HTTP service with operational endpoints for health, log enumeration, log retrieval, config read/write, and QQ message sending, which materially exceeds the stated installer/start/repair/smoke-test purpose. Even on localhost, this broad control plane creates an attack surface for local malware, browser-based localhost abuse, or unintended operator exposure, especially because it can alter runtime behavior and access message data.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The /logs, /logs/:filename, /config, and POST /config endpoints are unauthenticated, allowing any requester to read chat logs, inspect secrets/configuration, and mutate runtime settings. That combination enables both data exfiltration and control of downstream behavior, including changing service endpoints or tokens to redirect traffic or disrupt the bridge.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The /send_qq endpoint accepts unauthenticated requests and can send arbitrary messages to QQ targets through the bridge. This effectively turns the service into an open local messaging relay that can be abused by any local process, misconfigured network exposure, or browser-driven localhost request to impersonate the bot or spam users/groups.

Credential Access

High
Category
Privilege Escalation
Content
bridge_cfg = read_json(config_dir / "bridge.json", {})
    webui_cfg = read_json(config_dir / "webui.json", {})
    env_cfg = {}
    env_path = config_dir / ".env"
    if env_path.exists():
        for line in env_path.read_text(encoding="utf-8").splitlines():
            if "=" in line:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
bridge_cfg = read_json(config_dir / "bridge.json", {})
    webui_cfg = read_json(config_dir / "webui.json", {})
    env_cfg = {}
    env_path = config_dir / ".env"
    if env_path.exists():
        for line in env_path.read_text(encoding="utf-8").splitlines():
            if "=" in line:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill describes and directs use of powerful capabilities including file read/write, shell execution, and network access, but it does not declare any explicit tool scope or permission boundaries. In an agent ecosystem, this weakens governance and review because consumers cannot easily tell what the skill is allowed to do, increasing the risk of over-privileged execution and unintended destructive actions on the host.

External Transmission

Medium
Category
Data Exfiltration
Content
Download sources used by the bundled script:

- `https://api.github.com/repos/NapNeko/NapCatQQ/releases/latest`
- `winget install --id Tencent.QQ.NT --exact`

## Workflow
Confidence
79% confidence
Finding
The skill downloads software at runtime from public sources, including GitHub release metadata and Winget-installed QQ packages, which creates a supply-chain trust boundary. Even if the sources are legitimate, fetching the latest release dynamically without pinning versions or verifying cryptographic integrity can expose users to malicious upstream compromise, typosquatting, or unexpected breaking changes.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The code persistently stores chat content to disk and maintains conversation context in memory, despite the skill being described as an installer/repair utility rather than an always-on chat data processor. This creates undisclosed collection and retention of potentially sensitive user communications, increasing privacy and confidentiality risk if the host is shared or compromised.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Writing user message content to disk without clear disclosure or consent is a genuine privacy/security issue because chat logs may contain sensitive personal or operational information. In the context of an installer-labeled skill, this is more concerning because users would not reasonably expect ongoing content retention beyond setup tasks.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
Incoming message data is sent to NapCat/OpenClaw-related services as part of bridge operation, which may be functionally necessary, but it is still undisclosed data transmission. The main risk is privacy and expectation mismatch: users interacting with QQ may not know their content is being forwarded to another local service for processing.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This function launches `wsl` and `docker exec` to run an external agent process, which is a significant system operation. While subprocess execution may be part of the bridge's purpose, the code shown provides no nearby user-facing notice, comment, or docstring explaining that external commands will be run on the host.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This batch script performs destructive operational actions by forcibly killing local Windows processes and a process inside WSL/Docker using taskkill /f and pkill, but it provides no pre-action warning, confirmation prompt, or explanatory comment before doing so. Although it prints status messages after each action, those messages do not disclose the impact in advance or give the user a chance to avoid stopping potentially unrelated QQ or gateway processes.

External Transmission

Medium
Category
Data Exfiltration
Content
DEFAULT_ROOT = Path.home() / "NapCat.OpenClaw"
DEFAULT_QQ_PACKAGE_ID = "Tencent.QQ.NT"
DEFAULT_NAPCAT_RELEASE_API = "https://api.github.com/repos/NapNeko/NapCatQQ/releases/latest"
DEFAULT_NAPCAT_ASSET = "NapCat.Shell.Windows.Node.zip"
DEFAULT_CONTAINER_IMAGE = "node:23-bookworm"
DEFAULT_BRIDGE_PORT = 3002
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_command(args: list[str], *, cwd: Path | None = None, check: bool = True) -> subprocess.CompletedProcess[str]:
    printable = " ".join(shlex.quote(part) for part in args)
    print(f"+ {printable}")
    completed = subprocess.run(
        args,
        cwd=str(cwd) if cwd else None,
        text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The smoke test can send a real private QQ message to the configured admin account when the bridge is online, without an explicit prompt or confirmation at execution time. That can cause unintended outbound communication, privacy surprises, and operational confusion because a diagnostic action triggers contact with a live account.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script can install software via winget, download and extract binaries from GitHub, write configuration and batch files, and optionally create/start a Docker container, yet it does not present an explicit confirmation or safety warning before making these host changes. In a skill/agent context, that raises the risk of surprising or unintended system modification, especially if invoked indirectly or with incomplete user awareness.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
`toLocaleTimeString('zh-CN', ...)` hard-codes a locale choice, which is a natural-language/locale policy concern when no opt-in or justification is provided. The file does not indicate that the skill is intentionally region-specific or that users can override this locale behavior.

Static analysis

No suspicious patterns detected.