T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/vw_env_export.sh:44
- Finding
- Command Injection Through Unescaped Vault Values Sourced as Shell Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/vw_env_export.sh:44-48` and `scripts/vw_bootstrap.sh:39-41` **Vulnerability Type**: Shell command injection through unsafe code generation and `source` **Risk Level**: High ### Vulnerable Code ```bash cat <<EOF export BW_CLIENTID='$CID' export BW_CLIENTSECRET='$CSEC' export BW_PASSWORD='$CPW' EOF ``` The generated output is executed by the bootstrap script: ```bash EXPORTED="$("$SCRIPT_DIR"/vw_env_export.sh)" || _vw_fail "vw_env_export.sh failed" # shellcheck disable=SC1090 source /dev/stdin <<< "$EXPORTED" ``` ### Technical Analysis The export helper inserts Vaultwarden password values directly into single-quoted shell assignments. It does not escape single quotes, line breaks, command substitutions, or other shell syntax. Single quotes only protect the value while the parser remains inside the quoted string. A vault value containing a single quote can terminate that string and append arbitrary shell commands. Although command substitution embedded entirely inside a valid single-quoted value would not execute, an attacker can escape the generated quoting first. The bootstrap script captures the generated text and passes it to Bash's `source` built-in. Consequently, the generated text is treated as executable shell code rather than inert data. This converts control over any selected vault value into command execution. For example, a selected password could contain a payload structurally equivalent to: ```text '; id > /tmp/vw-injected; # ``` This would produce shell source resembling: ```bash export BW_PASSWORD=''; id > /tmp/vw-injected; #' ``` ### Attack Path 1. An attacker gains permission to create or modify one of the selected Vaultwarden items, or causes an attacker-controlled item to be selected through the helper's ambiguous search behavior. 2. The attacker sets the item's password to a value that closes the generated single-quoted assignment and appends a shell command. 3. A vict ...[truncated 901 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Do not serialize secrets as shell source code and do not execute generated content with `source`. Refactor the bootstrap so values are assigned directly in the current process through a data-only interface. Suitable approaches include: 1. Move the retrieval logic into the sourced bootstrap script and assign command output directly to fixed variables. 2. Return a structured data format such as JSON and parse it without evaluating the values as shell syntax. 3. Use a dedicated process that consumes the secrets without exporting them into a broad shell environment. If shell assignment serialization is unavoidable, use Bash's `%q` escaping for every value: ```bash printf 'export BW_CLIENTID=%q\n' "$CID" printf 'export BW_CLIENTSECRET=%q\n' "$CSEC" printf 'export BW_PASSWORD=%q\n' "$CPW" ``` Even with escaping, avoid `source` where possible. Validate the generated record count, use fixed variable names, reject unexpected output, minimize the lifetime of sensitive environment variables, and clear them after use. ]]>
