Back to skill

Security audit

qBittorrent Skill

Security checks for vulnerabilities and agentic risk

Overview

This qBittorrent skill is mostly purpose-aligned, but it exposes broad app-changing and destructive controls while handling credentials and session tokens insecurely.

Review before installing. Use this only with a trusted qBittorrent WebUI endpoint, prefer HTTPS except for localhost, protect any credential file with owner-only permissions, and avoid letting an agent run delete --files or set-preferences unless you have explicitly confirmed the target torrent or exact settings change.

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

T09 · Insecure Skill Coding Practices

Warning
Location
README.md:26
Finding

Credential File Is Created Without Restrictive Permissions

Content
View full analysis
~/.clawdbot/credentials/qbittorrent/config.json << 'EOF' { "url": "http://localhost:8080", "username": "admin", "password": "your-password-here" } EOF ``` The resulting file is subsequently consumed as a credential source: ```bash if [[ -f "$CONFIG_FILE" ]]; then QBIT_URL=$(jq -r '.url // empty' "$CONFIG_FILE") QBIT_USER=$(jq -r '.username // empty' "$CONFIG_FILE") QBIT_PASS=$(jq -r '.password // empty' "$CONFIG_FILE") fi ``` ### Technical Analysis The documented setup stores the qBittorrent username and password as plaintext JSON. Plaintext storage is necessary for the current authentication design, but the setup does not apply a restrictive umask or explicitly set directory and file permissions. The final permissions therefore depend on the user's existing umask. With a permissive configuration, other local users may be able to read the qBittorrent credentials. The credential-directory path is legitimate and does not exceed the functional scope of the Skill, but access to it should be restricted to the owning user. There is also a documentation inconsistency: `README.md` uses `~/.clawdbot/credentials/qbittorrent/config.json`, while `SKILL.md:13` and `scripts/qbit-api.sh:7` use `~/.openclaw/credentials/qbittorrent/config.json`. This primarily causes configuration failures rather than creating a separate vulnerability. ### Attack Path 1. A user follows the documented setup commands. 2. The credential file is created using the user's current umask, without an explicit `0600` mode. 3. On a multi-user system with permissive home-directory and file permissions, another local account enumerates the documented credential path. 4. The attacker reads the qBittorrent URL, us ...[truncated 751 chars]
Remediation
View remediation
"$HOME/.openclaw/credentials/qbittorrent/config.json" <<'EOF' { "url": "https://your-qbit-host:8080", "username": "admin", "password": "your-password-here" } EOF chmod 600 "$HOME/.openclaw/credentials/qbittorrent/config.json" ``` Additional hardening should include: 1. Standardize all documentation and code on the same configuration path. 2. Have the script reject credential files not owned by the current user. 3. Warn or fail when the file is group-readable or world-readable. 4. Recommend a dedicated, least-privileged qBittorrent account where supported. 5. Prefer an operating-system credential store or secret manager instead of persistent plaintext storage. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/qbit-api.sh:29
Finding

Credentials and Session Data Can Be Transmitted Over Plain HTTP

Content
View full analysis
&1) if echo "$resp" | grep -iq "set-cookie: SID="; then local sid sid=$(echo "$resp" | grep -ioP 'SID=\K[^;]+') echo "$sid" > "$COOKIE_FILE" return 0 else echo "Login failed" >&2 return 1 fi } ``` The documented configuration explicitly uses HTTP: ```json { "url": "http://localhost:8080", "username": "admin", "password": "your-password-here" } ``` ### Technical Analysis The script submits the username and password as URL-encoded form data to the configured WebUI URL. It accepts the URL without validating its scheme, while the documentation encourages an `http://` endpoint. When the endpoint is not strictly confined to a trusted loopback connection, HTTP provides neither confidentiality nor server authentication. An observer can inspect the login request and recover the username and password. The returned `SID` session cookie and subsequent authenticated API requests are also exposed to interception or modification. Accessing the configured qBittorrent endpoint is necessary for the Skill's declared functionality. Allowing credentials to traverse an untrusted network without TLS is not necessary. ### Attack Path 1. The user configures an HTTP qBittorrent WebUI endpoint, particularly one hosted on another machine. 2. The Skill invokes `do_login` and sends the username and password in an unencrypted HTTP POST request. 3. An attacker with access to the local network, wireless network, proxy, router ...[truncated 795 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/qbit-api.sh:8
Finding

Predictable Shared Temporary File Exposes the qBittorrent Session Token

Content
View full analysis
&1) if echo "$resp" | grep -iq "set-cookie: SID="; then local sid sid=$(echo "$resp" | grep -ioP 'SID=\K[^;]+') echo "$sid" > "$COOKIE_FILE" return 0 else echo "Login failed" >&2 return 1 fi } # Ensure we have a valid session ensure_session() { if [[ ! -f "$COOKIE_FILE" ]]; then do_login return fi # Test session validity local sid sid=$(cat "$COOKIE_FILE") local resp resp=$(curl -sS -o /dev/null -w "%{http_code}" \ --cookie "SID=$sid" \ "$QBIT_URL/api/v2/app/version") if [[ "$resp" != "200" ]]; then do_login fi } ``` ### Technical Analysis The session identifier is written to a deterministic path under the globally shared `/tmp` directory. The filename is derived only from the numeric user ID and is therefore predictable. The script does not: - Create the file atomically. - Enforce mode `0600`. - Verify file ownership. - Reject symbolic links or non-regular files. - Use a user-private runtime directory. - Remove the token when execution finishes. Under a normal umask such as `022`, a newly created file may be readable by other users. A local attacker may also pre-create the predictable path. Depending on operating-system symlink protections and file ownership rules, this can result in denial of service, token replacement, or redirection of the write to another victim-writable file. The cookie ...[truncated 1693 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% 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).

Content

Scanner excerpt · scripts/qbit-api.sh (reported line 96)May include surrounding context.

sh
files <hash>                   Get torrent files
  trackers <hash>                Get torrent trackers
  
  add <url|magnet> [--category C] [--tags T] [--paused] [--skip-check]
  add-file <path> [--category C] [--tags T] [--paused]
  
  pause <hash|all>               Pause torrent(s)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% 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).

Content

Scanner excerpt · scripts/qbit-api.sh (reported line 187)May include surrounding context.

sh
files <hash>                   Get torrent files
  trackers <hash>                Get torrent trackers
  
  add <url|magnet> [--category C] [--tags T] [--paused] [--skip-check]
  add-file <path> [--category C] [--tags T] [--paused]
  
  pause <hash|all>               Pause torrent(s)

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script exposes set-preferences, which can modify arbitrary application-wide qBittorrent settings via a raw JSON string. This exceeds the manifest's stated torrent-management scope and enables high-impact changes such as network bindings, save paths, external integration settings, or other global behavior that a user may not expect this skill to control.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
87% confidence
Finding

The documentation instructs users to store qBittorrent WebUI credentials in a persistent plaintext JSON file under the home directory. If local filesystem access is obtained by another process, user, backup system, or logs/scripts that expose this file, an attacker could recover credentials and remotely control torrent operations through the WebUI.

Content

Scanner excerpt · README.md (reported line 23)May include surrounding context.

  1. Set a username and password
  2. Note the port (default: 8080)

2. Create Credentials File

bash
mkdir -p ~/.clawdbot/credentials/qbittorrent

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The markdown describes delete <hash> and delete <hash> --files as normal usage examples, but it does not warn that these actions can permanently remove torrent entries and local files. For markdown files, omissions of warnings about behaviors affecting user data or system integrity should be flagged.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill documents and relies on shell-based command execution (./scripts/qbit-api.sh ...) but does not declare any explicit tool scope such as permissions or allowed-tools. This weakens sandboxing and reviewability, increasing the risk that an agent may invoke shell capabilities more broadly than intended when handling torrent-management requests.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documentation includes destructive deletion commands, including delete <hash> --files, without an explicit warning that content may be permanently removed. In an agent context, this can lead to accidental or insufficiently confirmed data loss, especially because torrent hashes are opaque and users may not recognize the full consequence of the action.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/qbit-api.sh (reported line 32)May include surrounding context.

sh
# Login and get session cookie
do_login() {
    local resp
    resp=$(curl -sS -i -X POST \
        -H "Referer: $QBIT_URL" \
        -d "username=$QBIT_USER&password=$QBIT_PASS" \
        "$QBIT_URL/api/v2/auth/login" 2>&1)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code performs a network request that sends the configured username and password to the qBittorrent WebUI login endpoint. Although the operation is part of authentication, the script provides no confirmation prompt or user-facing notice at the point of transmission, so users may not realize stored credentials are being sent over the network.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script stores the authenticated SID session token in a predictable file under /tmp and reuses it across calls. On multi-user systems or in weakly permissioned environments, another local actor could read or replace this file to hijack the qBittorrent session or interfere with requests.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest frames this skill as torrent-management functionality such as listing, adding, pausing, resuming, deleting torrents, checking status, speed, and stats. However, the CLI also advertises access to global app preferences and the ability to change them, which goes beyond managing torrents and into reconfiguring the qBittorrent application itself.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/qbit-api.sh (reported line 221)May include surrounding context.

sh
[[ -n "$category" ]] && args+=(-F "category=$category")
    [[ -n "$tags" ]] && args+=(-F "tags=$tags")
    
    curl -sS --cookie "SID=$sid" -H "Referer: $QBIT_URL" "${args[@]}" "$QBIT_URL/api/v2/torrents/add"
    echo '{"status": "ok"}'
}