Report security vulnerabilities through the GitHub Security tab. Do not open a public GitHub issue for security vulnerabilities.
| Version | Supported |
|---|---|
| 1.3.x | Yes |
| 1.2.x | No — upgrade to 1.3.x |
| Older | No — upgrade to latest |
bwx is a pure-bash CLI with no compiled code. Its attack surface
comes entirely from its runtime dependencies:
| Dependency | Source | Used when | Security concern |
|---|---|---|---|
| bash (4.0+) | System package | Always | OS-level updates; no bwx-specific risk |
| jq | Native or Docker apteno/alpine-jq |
Parsing BWS API JSON | Docker image may contain Alpine CVEs |
| bws | Native or Docker bitwarden/bws |
All BWS API operations | Docker image may contain OS/binary CVEs |
| curl | Native or Docker curlimages/curl |
Provider calls, HTTP fallback | Docker image may contain Alpine CVEs |
| openssl | Native or Docker alpine/openssl |
Self-signed cert generation | Docker image may contain Alpine CVEs |
| aws | Native or Docker amazon/aws-cli |
IAM key rotation (aws-iam) |
Docker image may contain AL2 CVEs |
When native jq, bws, or curl are not installed, bwx falls back
to Docker-wrapped alternatives. The default image references are:
| Variable | Default | Purpose |
|---|---|---|
BWX_JQ_IMAGE |
apteno/alpine-jq |
jq wrapper |
BWX_BWS_IMAGE |
bitwarden/bws:latest |
Bitwarden CLI wrapper |
BWX_CURL_IMAGE |
curlimages/curl |
HTTP client and provider API calls |
BWX_OPENSSL_IMAGE |
alpine/openssl |
TLS certificate generation |
BWX_AWS_IMAGE |
amazon/aws-cli |
AWS IAM key rotation |
To pin a specific image version (recommended for production):
export BWX_JQ_IMAGE="apteno/alpine-jq:2023-01-01"
export BWX_BWS_IMAGE="bitwarden/bws:2025.1.0"
export BWX_CURL_IMAGE="curlimages/curl:8.11.1"
export BWX_OPENSSL_IMAGE="alpine/openssl:3.4.1"
export BWX_AWS_IMAGE="amazon/aws-cli:2.27.0"Stage 4 of the build scans all dependency images for HIGH and CRITICAL CVEs using Trivy:
./build # includes dependency image scan
./build --dry-run # shows which images would be scannedThe scan is advisory (does not block the build) because the
vulnerabilities are in third-party images that bwx cannot patch
directly. When a CVE is found, update the default pin in
include/tools or include/http, or override via the environment
variables above.
BWS_ACCESS_TOKEN is passed to the bws CLI (or Docker container)
via environment variable. This means:
- The token is visible in
docker inspectoutput while a container is running (Docker wrapper only). - The token is visible in
/proc/<pid>/environon Linux to processes running as the same user. - The token is written to disk by
bwxonly when you ask for it, viabwx config set bws-access-token.
Recommendations:
- On shared hosts, prefer a native
bwsinstall over the Docker wrapper to avoiddocker inspectexposure. - Never persist the token in
.bashrc,.profile, or any other shell startup file. Those files are frequently mode0644, they are read by every interactive shell, and they are easy to commit to a dotfiles repository by accident. Usebwx config setinstead. - Pipe the token into
bwx config setrather than passing it as an argument: an argument is visible in the process table and is recorded in shell history. - Use Bitwarden machine account tokens scoped to the minimum required project.
bwx config set writes to
${BWX_CONFIG_DIR:-${XDG_CONFIG_HOME:-${HOME}/.config}/bwx}. Files
holding credential material:
- Are written with mode
0600inside a directory with mode0700. - Are written through a temporary file and renamed into place, so a concurrent reader never observes a partial value.
- Are refused on read when group or other holds any permission
bit, in the same spirit as
sshrejecting a world-readable private key. The refusal names the file and the fix.
The permission check runs only when a file is actually read. When the environment already supplies the value, the file is never opened and never inspected, so a stale over-permissive file cannot break a caller that does not depend on it.
Non-credential entries (currently bwx-default-project, a project
identifier) are classified separately and are not mode-enforced.
bwx secret list and bwx project list cache API responses in
temporary files under ${BWX_CACHE_DIR:-${XDG_CACHE_HOME:-${HOME}/.cache}/bwx}. Cache
files:
- Are readable only by the owning user (mode 0600).
- Contain secret metadata (keys, notes, UUIDs) but not secret values (values are fetched individually and not cached).
- Expire after
BWX_SECRET_LIST_CACHE_TTL_SECONDS(default: 300). - Are overwritten on
--refresh.
On multi-user systems, verify that TMPDIR points to a
user-private directory (e.g., /tmp/user-$(id -u)).
| Measure | How |
|---|---|
| No compiled code | Pure bash; no binary supply chain |
| Shellcheck clean | All scripts pass shellcheck with no suppressed warnings |
| Minimal dependencies | Only bash + Docker required; jq/bws/curl are optional native installs |
| Docker wrapper isolation | Fallback containers run with --rm (no persistent state) |
| Input validation | Secret names and project names are validated before passing to bws |
| No secrets on disk | BWS_ACCESS_TOKEN stays in the environment; secret values are not cached |
| Pinned CI tool versions | Build script pins shellcheck, markdownlint, kcov, and scc image tags |