Back to skill

Security audit

Qbittorrent

Security checks for vulnerabilities and agentic risk

Overview

This qBittorrent management skill is mostly purpose-aligned, but it handles credentials and deletion authority in ways that need user review before installation.

Review this before installing if qBittorrent controls important or private downloads. Use a local-only or HTTPS WebUI, protect the credential file with restrictive permissions, avoid shared machines, and require explicit user confirmation before running delete operations, especially `--files`.

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<![CDATA[ ## Vulnerability Details **File Location**: `README.md:26-34` **Vulnerability Type**: Plaintext credential file with unspecified access permissions **Risk Level**: Medium ```bash mkdir -p ~/.clawdbot/credentials/qbittorrent cat > ~/.clawdbot/credentials/qbittorrent/config.json << 'EOF' { "url": "http://localhost:8080", "username": "admin", "password": "your-password-here" } EOF ``` ### Technical Analysis The documented setup stores the qBittorrent username and password in plaintext but does not apply restrictive permissions to either the credential directory or the resulting file. Their effective permissions therefore depend on the user's current `umask`. Access to qBittorrent credentials is necessary for the declared WebUI management functionality and does not inherently exceed least privilege. The weakness is the absence of controls ensuring that only the account running the Skill can read the credentials. On a multi-user system with a permissive `umask`, the file may be readable by other local users. The documentation also does not warn users that the file contains a reusable password. ### Attack Path 1. A user follows the documented setup commands with a permissive `umask`. 2. The resulting `config.json` is created with group-readable or world-readable permissions. 3. Another local user reads `~/.clawdbot/credentials/qbittorrent/config.json`. 4. The attacker extracts the qBittorrent WebUI URL, username, and password. 5. If the WebUI is reachable by the attacker, those credentials are used to authenticate and invoke management APIs. ### Impact Assessment Successful exploitation grants the privileges associated with the configured qBittorrent WebUI account. This can include: - Viewing torrent names, trackers, tags, categories, and save paths. - Adding or controlling torrents. - Changing transfer limits. - Removing torrents. - Deleting downloaded files through the WebUI deletion API. The issue does not directly grant operating-syste ...[truncated 58 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Set a restrictive `umask` before creating credential material and explicitly enforce permissions: ```bash umask 077 install -d -m 700 "$HOME/.clawdbot/credentials/qbittorrent" cat > "$HOME/.clawdbot/credentials/qbittorrent/config.json" <<'EOF' { "url": "http://localhost:8080", "username": "admin", "password": "your-password-here" } EOF chmod 600 "$HOME/.clawdbot/credentials/qbittorrent/config.json" ``` The script should also validate before reading the file that it is: - A regular file rather than a symbolic link. - Owned by the current user. - Not readable or writable by group or other users. Where supported by the hosting environment, prefer a dedicated secret store over a long-lived plaintext password file. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/qbit-api.sh:7
Finding
Session identifier is stored in a predictable shared temporary path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/qbit-api.sh:7, 30-40` **Vulnerability Type**: Unsafe temporary file and insecure session-token storage **Risk Level**: Medium ```bash COOKIE_FILE="${QBIT_COOKIE:-/tmp/qbit_cookie_$(id -u).txt}" ``` ```bash 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) if echo "$resp" | grep -iq "set-cookie: SID="; then local sid sid=$(echo "$resp" | grep -ioP 'SID=\K[^;]+') echo "$sid" > "$COOKIE_FILE" return 0 ``` ### Technical Analysis The qBittorrent session identifier is written to a deterministic path under the globally shared `/tmp` directory. The filename is derived only from the user ID and is reused across executions. The script does not: - Create the file atomically with exclusive ownership. - Apply mode `0600`. - Confirm that the destination is a regular file owned by the current user. - Reject symbolic links or other unexpected file types. - Remove the session file when execution finishes. The actual mode is inherited from the user's `umask`; with a common permissive `umask`, the session identifier may become readable by other local users. Predictable shared temporary paths can also permit pre-creation or link-based interference where platform-level temporary-file protections are absent or disabled. The `QBIT_COOKIE` override is useful operationally, but an unsafe caller-provided destination receives no validation either. ### Attack Path 1. The victim runs the script and authenticates to qBittorrent. 2. The script writes the valid SID to `/tmp/qbit_cookie_<uid>.txt`. 3. A local attacker reads the file if its permissions permit access, or exploits predictable-path behavior on a system without sufficient temporary-file protections. 4. The attacker sends API requests containing `SID=<stolen-value>` to the confi ...[truncated 894 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Store session state in a private runtime directory and create the file atomically: ```bash umask 077 runtime_dir="${XDG_RUNTIME_DIR:-}" if [[ -z "$runtime_dir" || ! -d "$runtime_dir" || ! -O "$runtime_dir" ]]; then runtime_dir=$(mktemp -d) trap 'rm -rf -- "$runtime_dir"' EXIT fi COOKIE_FILE="${QBIT_COOKIE:-$(mktemp "$runtime_dir/qbit-cookie.XXXXXX")}" chmod 600 "$COOKIE_FILE" ``` Additional hardening should include: 1. Rejecting a configured cookie path if it is a symbolic link. 2. Verifying that any existing file is regular, owned by the current user, and mode `0600`. 3. Using `mktemp` rather than a UID-derived filename. 4. Removing the session file after use unless persistent sessions are explicitly required. 5. Avoiding persistence entirely by keeping the SID in memory for a single invocation where practical. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/qbit-api.sh:30
Finding
Credentials and session traffic can be transmitted over cleartext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/qbit-api.sh:30-33` **Vulnerability Type**: Cleartext transmission of authentication credentials **Risk Level**: Medium ```bash 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) ``` The documented configuration explicitly uses HTTP: ```json { "url": "http://localhost:8080", "username": "admin", "password": "your-password-here" } ``` ### Technical Analysis The script accepts an arbitrary `QBIT_URL` and directly sends the username and password to its authentication endpoint. It does not require HTTPS, restrict cleartext HTTP to loopback addresses, or warn before transmitting credentials to a remote HTTP endpoint. The documented `http://localhost:8080` default limits exposure when qBittorrent and the Skill execute on the same trusted host. However, the README describes the WebUI as a remote-control interface, and the configuration can be changed to a non-loopback HTTP URL without any protection. All subsequent authenticated API requests also send the SID cookie over the selected transport. Consequently, either the reusable password or authenticated session can be intercepted on an untrusted network. ### Attack Path 1. A user configures `QBIT_URL` with a remote `http://` address. 2. The script sends the qBittorrent username and password in an unencrypted HTTP request. 3. A network-positioned attacker observes or modifies the request. 4. The attacker captures the credentials or the resulting SID. 5. The attacker authenticates to the WebUI or reuses the session token. 6. The attacker invokes torrent management or deletion operations using the victim's privileges. ### Impact Assessment An attacker who intercepts the reusable credentials can retain access until the password changes. An intercepted SID provides access for the lifetime of that session. The resulting scope is the configured qBi ...[truncated 264 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Validate the configured URL before authentication: - Permit `http://` only for verified loopback destinations such as `localhost`, `127.0.0.1`, or `[::1]`. - Require `https://` for all non-loopback endpoints. - Fail closed with a clear error rather than silently accepting remote cleartext transport. - Document how to configure a trusted TLS certificate for the qBittorrent WebUI or a local reverse proxy. - Do not recommend disabling TLS certificate verification. For exceptional environments where remote HTTP is unavoidable, require an explicit high-risk opt-in and prominently warn that both credentials and session cookies can be intercepted. A trusted VPN or SSH tunnel can also protect access to a loopback-only WebUI. ]]>
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 (11)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
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)
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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
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)
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).

Session Persistence

Medium
Category
Rogue Agent
Content
4. Set a username and password
5. Note the port (default: 8080)

### 2. Create Credentials File

```bash
mkdir -p ~/.clawdbot/credentials/qbittorrent
Confidence
88% confidence
Finding
The README instructs users to store qBittorrent WebUI credentials in a persistent plaintext JSON file under the home directory, and also shows use of HTTP rather than HTTPS. If the local account, backups, logs, or filesystem permissions are exposed, these credentials can be recovered and used to control torrents remotely via the WebUI.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README documents `delete <hash>` and `delete <hash> --files`, including an option that deletes downloaded files, but it does not warn that the `--files` variant is destructive and may permanently remove user data. For markdown files, safety-impacting behaviors should be disclosed clearly so users understand the risk before invoking the skill.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill documents and relies on shell-capable scripts but does not declare any explicit tool scope or permission boundaries. In an agent setting, this increases the chance the skill can invoke shell actions without clear restriction, which broadens the blast radius if the skill is triggered unexpectedly or handles untrusted input unsafely.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill explicitly documents destructive deletion, including deleting downloaded files, without any warning, confirmation requirement, or safety note. In this context, an agent could remove torrents or associated data based on an ambiguous or malicious prompt, causing irreversible data loss.

External Transmission

Medium
Category
Data Exfiltration
Content
# 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)
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
92% confidence
Finding
The script stores the authenticated qBittorrent session ID in a predictable file under /tmp, which can expose an active management session to other local processes or users if filesystem permissions or symlink handling are unsafe. Because this cookie grants API access, theft of the file may allow unauthorized torrent management without knowing the username and password.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The manifest describes a narrower set of actions such as listing, adding, pausing, resuming, deleting torrents, checking status, speed, and stats. The code additionally implements recheck/reannounce, category/tag mutation, category/tag listing, and full app preference access, which are broader management capabilities not reflected in that description.

External Transmission

Medium
Category
Data Exfiltration
Content
[[ -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"}'
}
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
97% confidence
Finding
The delete command can remove torrents and, with --files, also delete associated files, which is an irreversible operation affecting user data. The script performs the API call directly and only returns a generic success JSON, with no confirmation prompt or warning in the command help about the destructive behavior.

Static analysis

No suspicious patterns detected.