com um clique
security-review
A guided agent security review of amux, its CI/CD, and repo.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Menu
A guided agent security review of amux, its CI/CD, and repo.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Baseado na classificação ocupacional SOC
| name | security-review |
| description | A guided agent security review of amux, its CI/CD, and repo. |
Conduct a systematic security review of amux across five domains: container security, network and API security, secrets and credentials, CI/CD supply chain, and codebase hygiene. Work through each section in order. For each finding, note the file path and line number, the severity (Critical / High / Medium / Low / Info), and a one-sentence description of the risk. Collect all findings, then print a summary table at the end.
Containers are amux's primary security boundary. Verify that boundary is correctly enforced.
Check every Dockerfile in templates/ and .amux/:
find templates/ .amux/ -name 'Dockerfile.*' | sort
For each file:
USER amux (or another non-root user) before the final CMD/ENTRYPOINT. Flag any image that runs as root.curl … | bash or curl … | sh patterns. Each one is a supply-chain risk: the remote server can serve arbitrary code. Note the URL and whether a checksum or signature is verified.
grep -n 'curl.*|.*sh\|curl.*sh.*bash' templates/Dockerfile.* .amux/Dockerfile.*
= x.y.z or --locked). Unpinned installs allow silent version drift.ENV, ARG, or COPY that brings a credential, token, or private key into the image layer.
grep -niE 'ENV.*(KEY|TOKEN|SECRET|PASSWORD|PASS)\s*=' templates/Dockerfile.* .amux/Dockerfile.*
Read src/runtime/docker.rs (and src/runtime/apple_containers.rs if present). For each --volume / -v / --mount flag passed to docker run:
.ssh). Confirm it is mounted read-only (:ro). If it is read-write, flag it High.
grep -n '\.ssh' src/runtime/docker.rs
/var/run/docker.sock). This gives the container the ability to spawn sibling containers and is a known container-escape vector. Confirm whether the mount exists, whether it is documented, and whether it is required by any agent workflow.
grep -n 'docker.sock' src/runtime/docker.rs
overlays.directories[].permission is converted to a :ro/:rw flag. Verify that omitting the field defaults to read-only, not read-write.
grep -n 'overlay\|permission\|":ro"\|":rw"' src/runtime/docker.rs
Find where envPassthrough values are injected into docker run:
grep -rn 'env_passthrough\|envPassthrough\|passthrough' src/ --include='*.rs'
Confirm that:
-e NAME=VALUE to Docker. If the names are baked into the image or config file, flag it..amux/config.json for actual secrets embedded as values, not just names).
cat .amux/config.json
Check that no container is launched with --privileged, --cap-add=ALL, or dangerous individual capabilities (SYS_ADMIN, NET_ADMIN, SYS_PTRACE):
grep -n 'privileged\|cap-add\|cap_add\|SYS_ADMIN\|NET_ADMIN\|SYS_PTRACE' src/runtime/docker.rs
Flag any match as High unless accompanied by a documented justification.
Read src/commands/headless/server.rs. Find the TcpListener::bind call and record the address:
grep -n 'bind\|0\.0\.0\.0\|127\.0\.0\.1' src/commands/headless/server.rs
0.0.0.0, it accepts connections from any network interface (LAN, VPN, etc.), not just localhost. This is Medium if auth is required, High if --dangerously-skip-auth is used without warnings.127.0.0.1, it is only accessible locally — flag this as Info (good practice).Check whether the headless server supports TLS. Search for rustls, tls, https in the server and config files:
grep -rn 'tls\|rustls\|https' src/commands/headless/ --include='*.rs'
If TLS is absent, the API key and all command payloads travel in plaintext. Flag this High for any deployment where the server is reachable over a non-loopback interface.
Read src/commands/headless/auth.rs. Verify:
--dangerously-skip-auth flag — Confirm it exists and check whether amux emits a prominent warning when it is used.
grep -n 'skip.auth\|dangerously' src/commands/headless/server.rs src/commands/headless/auth.rs
subtle::ConstantTimeEq or equivalent. A standard == comparison leaks key length via timing. Flag any == on key bytes as High.
grep -n 'ConstantTimeEq\|constant_time\|== key\|== hash' src/commands/headless/auth.rs
ring::rand::SecureRandom (32+ bytes). A short or PRNG-derived key is High.
grep -n 'SecureRandom\|rand\|generate' src/commands/headless/auth.rs
Locate the stored key hash file and its permissions:
grep -n 'api_key\|0o600\|mode(' src/commands/headless/auth.rs
Verify:
0o600 on Unix (owner read/write only). Any looser mode (e.g., 0o644) exposes the hash.For the headless server, find how headless.workDirs is enforced:
grep -rn 'work_dirs\|workDirs\|allowlist\|allowed' src/commands/headless/ --include='*.rs'
Confirm that any path not in the allowlist is rejected before the container is started, not after. If the check is missing or happens post-launch, flag it High.
Search the entire Rust source tree and config files for patterns that look like embedded credentials:
grep -rn --include='*.rs' -E \
'(api[_-]?key|secret|token|password|passwd|credential)\s*=\s*"[^"]' \
src/ tests/
grep -rn --include='*.json' -E \
'"(key|secret|token|password)":\s*"[^{]' \
.amux/ aspec/
Any match outside of test fixtures or documentation is Critical if it looks like a real credential.
Check recent commits and any committed config files for accidentally included secrets:
git log --all --oneline | head -50
git diff HEAD~10..HEAD -- '*.json' '*.toml' '*.env' '*.yaml' '*.yml' | \
grep -E '^\+.*(key|secret|token|password).*=' | grep -v '#'
If you find a secret in git history, flag it Critical — rotating the credential is required even after a history rewrite.
Read src/commands/auth.rs. The Claude agent auth reads from the macOS keychain:
grep -n 'security\|keychain\|accessToken\|CLAUDE_CODE_OAUTH_TOKEN' src/commands/auth.rs
Verify:
security find-generic-password and injected only as an environment variable into the container — it is never written to disk or logged.auto_agent_auth_accepted is false, the user is prompted before the token is passed. Confirm the prompt path exists.Locate where Cline's ~/.cline/data/secrets.json is copied and mounted:
grep -rn 'cline\|secrets.json' src/runtime/docker.rs
Verify:
~/.cline). Direct mounts of the home subtree are a blast-radius risk.tasks/ and workspace/ directories under .cline/data/ are explicitly excluded from the mount. If they are included, flag it Medium.Read .github/workflows/test.yml and .github/workflows/release.yml:
cat .github/workflows/test.yml
cat .github/workflows/release.yml
Check:
pull_request_target trigger with secrets.* access is High).v[0-9]+.[0-9]+.[0-9]+). If it can be triggered on arbitrary branches or by external PRs, flag it High.For every uses: line in both workflows, check whether third-party actions are pinned to a full commit SHA or only to a mutable tag:
grep -n 'uses:' .github/workflows/*.yml
uses: actions/checkout@v4 — mutable tag; a compromise of that tag serves malicious code. Flag as Medium.uses: actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675 — commit SHA; immutable. This is the correct form.For each unpinned action, note the action name, the current tag, and whether it is from a trusted publisher (actions/, docker/, softprops/ with high download counts).
Check that no workflow step echoes, prints, or exports secrets to workflow logs:
grep -n 'echo.*SECRET\|echo.*TOKEN\|echo.*KEY\|run.*env' .github/workflows/*.yml
Also check for set-output or ::set-output used to forward secrets to downstream steps (deprecated but still dangerous).
Run a vulnerability scan against the locked dependency tree. If cargo-audit is not installed, note that it should be run:
cargo audit 2>&1 | head -80
If cargo-audit is unavailable:
# List all dependencies and their versions for manual review
cargo metadata --format-version 1 | \
python3 -c "import json,sys; pkgs=json.load(sys.stdin)['packages']; \
[print(f\"{p['name']}=={p['version']}\") for p in pkgs]" | sort
Flag any package with a known CVE as Critical (if a fix is available) or High (if no fix exists).
Read scripts/release.sh:
head -60 scripts/release.sh
Verify:
set -euo pipefail (or equivalent). Missing pipefail means silent failures in pipelines./dev/tty, not stdin — this prevents the script from running non-interactively in CI.--force or --yes-all flag that bypasses all confirmations. If it does, flag it Medium.gh auth status and environment-provided tokens.Confirm Cargo.lock is committed to the repository (it should be for a binary crate):
git ls-files Cargo.lock
A missing or gitignored Cargo.lock for a binary means CI builds can silently pick up newer (potentially vulnerable or breaking) dependency versions. Flag a missing lock as High.
Check for executable bits set on files that should not be executable (e.g., .rs, .toml, .json, .md):
git ls-files --stage | awk '$1 ~ /755|744/' | head -30
Scripts (scripts/release.sh) are expected to be executable. Source files, configs, and docs should not be. Flag unexpected 755 files as Low.
Check that common secret-bearing files are covered by .gitignore:
cat .gitignore
The following patterns should be present (or the files should not exist in the repo):
.env, .env.**.pem, *.key, *.p12, *.pfxsecrets.json, credentials.json~/.amux/config.json (global config — should not be in this repo)If any of these files are tracked by git:
git ls-files | grep -E '\.(env|pem|key|p12|pfx)$|secrets\.json|credentials\.json'
Flag any match as Critical.
Search for unsafe blocks in the source:
grep -rn 'unsafe' src/ --include='*.rs' | grep -v '^\s*//'
Each unsafe block is not automatically a vulnerability, but each one must be justified. For every match: read the surrounding context, determine whether the invariant required for safety is clearly upheld (documented with a // SAFETY: comment), and flag any undocumented unsafe as Medium.
Search for places where user-controlled data is passed to shell commands:
grep -rn 'Command::new\|std::process::Command\|shell\|exec' src/ --include='*.rs' | \
grep -v test | grep -v '#\[cfg(test'
For each match, check whether arguments are passed as separate arg() calls (safe) or concatenated into a single shell string with sh -c "..." (dangerous — command injection). Flag any sh -c that incorporates user input as High.
Find all places where user-supplied paths from config (overlays, workDirs, etc.) are used to construct file system paths:
grep -rn 'PathBuf\|path::Path\|canonicalize\|join(' src/ --include='*.rs' | head -40
Verify that paths from config are canonicalized and validated against an allowlist before use. A path like ../../etc/passwd in overlays.directories[].host should be rejected, not passed to docker run -v. Flag missing canonicalization as Medium.
After completing all sections, print a consolidated findings table in this format:
| # | Severity | Domain | File / Location | Finding |
|---|----------|------------------|----------------------------------------|---------------------------------------------------|
| 1 | High | Network | src/commands/headless/server.rs:NN | Headless server binds 0.0.0.0; no TLS in transit |
| 2 | Medium | Container | src/runtime/docker.rs:NN | Docker socket mounted; enables container escape |
| … | … | … | … | … |
Severity levels: Critical (exploit likely, immediate action), High (significant risk, fix before next release), Medium (risk with mitigating factors), Low (defence-in-depth gap), Info (good practice observed).
After the table, list: