本文へ移動
cccskills
無料GitHub で公開

security-review

A guided agent security review of amux, its CI/CD, and repo.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md15.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Security Review

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.


1. Container Security

Containers are amux's primary security boundary. Verify that boundary is correctly enforced.

1a. Agent image Dockerfiles

Check every Dockerfile in templates/ and .amux/:

find templates/ .amux/ -name 'Dockerfile.*' | sort

For each file:

  • Non-root user — Verify the file contains USER amux (or another non-root user) before the final CMD/ENTRYPOINT. Flag any image that runs as root.
  • Install scripts via curl — Search for 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.*
    
  • Package pinning — Check whether apt packages and tool versions are pinned (= x.y.z or --locked). Unpinned installs allow silent version drift.
  • Secrets baked in — Scan for any 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.*
    

1b. Mount configuration

Read src/runtime/docker.rs (and src/runtime/apple_containers.rs if present). For each --volume / -v / --mount flag passed to docker run:

  • Repo root scope — Verify amux mounts only the current directory or the Git repo root, never a parent directory above the repo root.
  • SSH key mount — Locate the SSH mount (search for .ssh). Confirm it is mounted read-only (:ro). If it is read-write, flag it High.
    grep -n '\.ssh' src/runtime/docker.rs
    
  • Docker socket mount — Locate the Docker socket mount (search for /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
    
  • Overlay permission enforcement — Find where 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
    

1c. envPassthrough handling

Find where envPassthrough values are injected into docker run:

grep -rn 'env_passthrough\|envPassthrough\|passthrough' src/ --include='*.rs'

Confirm that:

  • Only the variable names listed in config are forwarded — amux reads the value from the host environment at runtime and passes -e NAME=VALUE to Docker. If the names are baked into the image or config file, flag it.
  • No passthrough list is stored in a world-readable file (check the repo config at .amux/config.json for actual secrets embedded as values, not just names).
    cat .amux/config.json
    

1d. Privileged mode and capabilities

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.


2. Network and Headless API Security

2a. Bind address

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
  • If the server binds to 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.
  • If the server binds to 127.0.0.1, it is only accessible locally — flag this as Info (good practice).

2b. TLS / transport encryption

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.

2c. Authentication middleware

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
    
  • Constant-time comparison — The API key comparison must use 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
    
  • Key generation — Verify the key is generated with ring::rand::SecureRandom (32+ bytes). A short or PRNG-derived key is High.
    grep -n 'SecureRandom\|rand\|generate' src/commands/headless/auth.rs
    

2d. API key storage

Locate the stored key hash file and its permissions:

grep -n 'api_key\|0o600\|mode(' src/commands/headless/auth.rs

Verify:

  • The file is created with mode 0o600 on Unix (owner read/write only). Any looser mode (e.g., 0o644) exposes the hash.
  • On non-Unix platforms (Windows), confirm whether equivalent ACL restrictions are applied or document the gap.
  • The plaintext key is printed once to stdout and never written to disk. If it is logged to a file or stored in plaintext, flag it Critical.

2e. workDirs allowlist

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.


3. Secrets and Credential Handling

3a. Hardcoded secrets scan

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.

3b. Git history scan for secrets

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.

3c. OAuth token extraction (macOS keychain)

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:

  • The token is extracted from the keychain via security find-generic-password and injected only as an environment variable into the container — it is never written to disk or logged.
  • If auto_agent_auth_accepted is false, the user is prompted before the token is passed. Confirm the prompt path exists.

3d. Cline secrets mount

Locate where Cline's ~/.cline/data/secrets.json is copied and mounted:

grep -rn 'cline\|secrets.json' src/runtime/docker.rs

Verify:

  • The file is copied to a temp directory (not mounted directly from ~/.cline). Direct mounts of the home subtree are a blast-radius risk.
  • The copy is cleaned up after the container exits. If it persists, flag it Medium.
  • The tasks/ and workspace/ directories under .cline/data/ are explicitly excluded from the mount. If they are included, flag it Medium.

4. CI/CD and Supply Chain Security

4a. Workflow trigger scope

Read .github/workflows/test.yml and .github/workflows/release.yml:

cat .github/workflows/test.yml
cat .github/workflows/release.yml

Check:

  • test.yml — Should trigger on push/PR to all branches. Verify no secrets are injected into untrusted PR workflows (any pull_request_target trigger with secrets.* access is High).
  • release.yml — Should trigger only on version tags (v[0-9]+.[0-9]+.[0-9]+). If it can be triggered on arbitrary branches or by external PRs, flag it High.

4b. Action pinning

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).

4c. Secrets in workflow environment

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).

4d. Dependency audit

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).

4e. Release script safety

Read scripts/release.sh:

head -60 scripts/release.sh

Verify:

  • The script begins with set -euo pipefail (or equivalent). Missing pipefail means silent failures in pipelines.
  • Interactive prompts use /dev/tty, not stdin — this prevents the script from running non-interactively in CI.
  • The script does not accept a --force or --yes-all flag that bypasses all confirmations. If it does, flag it Medium.
  • No credentials are hardcoded; the script relies on gh auth status and environment-provided tokens.

4f. Cargo.lock committed

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.


5. Codebase Hygiene

5a. File permissions on committed files

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.

5b. Sensitive files not in .gitignore

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, *.pfx
  • secrets.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.

5c. Unsafe Rust

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.

5d. Command injection in shell invocations

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.

5e. Path traversal in config-driven paths

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.


6. Final Report

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:

  1. Immediate actions — Critical and High findings that should be fixed before the next release.
  2. Recommended improvements — Medium and Low findings worth tracking.
  3. Confirmed secure — Areas where the implementation is correct and intentional, so reviewers know these were checked.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

ane

無料

Use ane for ALL file exploration, discovery, reading, and editing unless the user states otherwise. `ane exec <file> --chord "<chord>"` handles reads (Yank), searches (List), and edits (Change, Delete, Replace, Append, Prepend, Insert). Prefer ane over builtin file tools and shell utilities like grep, sed, and cat.

日本語の概要は準備中です。原文の説明を表示しています。

prettysmartdev/ane142026年10月2日 更新

blog-post

無料

Write a blog post in the preferred style related to amux

日本語の概要は準備中です。原文の説明を表示しています。

prettysmartdev/ane142026年10月2日 更新

Prepare amux for a new release. Updates version numbers, docs, getting-started, release notes, and blog post. Does NOT run the release script.

日本語の概要は準備中です。原文の説明を表示しています。

prettysmartdev/ane142026年10月2日 更新

prettysmartdev のスキルをすべて見る

このスキルの問題を報告する