Analyze Dockerfiles and provide recommendations for creating secure containers following best practices
How this skill is triggered — by the user, by Claude, or both
Slash command
/secure-container-review:secure-container-reviewThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This SKILL helps create secure containers by analyzing Dockerfiles and providing recommendations for hardening container security.
This SKILL helps create secure containers by analyzing Dockerfiles and providing recommendations for hardening container security.
Every finding the skill reports is tagged with one or more control identifiers from the frameworks below. The full per-rule mapping appears in each rule's Maps to: line; the full citation source list and reporting format live in the "Reporting format" section further down. This summary exists so a reader knows up-front which catalogs the skill speaks.
The two controls that drive the largest number of findings are AC-6 (Least Privilege) and CM-7 (Least Functionality) — every form of "this doesn't belong in a production container" maps to one or both. The full table:
| Control | Family | What it means here | Rules |
|---|---|---|---|
| AC-6 — Least Privilege | Access Control | Non-root execution, no interactive admin path, restricted credential holders. | #3, #4, #6, #11, #12 |
| CM-7 — Least Functionality | Configuration Management | Only what the application needs. No build tools, no shells, no daemons, no diagnostic utilities, no extra package sources in the final image. | #2, #5, #6, #7, #10, #12, #13, #14 |
| CM-2 — Baseline Configuration | Configuration Management | The image's exact bytes are the baseline; digest pinning makes that concrete. | #9 |
| CM-6 — Configuration Settings | Configuration Management | Entrypoint form, FIPS mode, USER directive are configuration properties. | #3, #5, #6, #14 |
| CM-8 — System Component Inventory | Configuration Management | Knowing what's in the image at the byte level (paired with #9). | #9 |
| CM-11 — User-Installed Software | Configuration Management | Controlling what packages can be installed at build time. | #10, #13 |
| AC-17 — Remote Access | Access Control | Removed at the image level (no SSH server). | #12 |
| IA-5 — Authenticator Management | Identification & Authentication | Credentials must not live in image layers. | #11 |
| SC-7 — Boundary Protection | System & Communications Protection | Hermetic builds, no arbitrary outbound fetches at build time. | #7 |
| SC-8 — Transmission Confidentiality | System & Communications Protection | FIPS-validated crypto for TLS. | #14 |
| SC-12 — Cryptographic Key Establishment | System & Communications Protection | Secrets and key material handling. | #11, #14 |
| SC-13 — Cryptographic Protection | System & Communications Protection | FIPS mode for cryptographic operations. | #14 |
| SC-18 — Mobile Code | System & Communications Protection | curl | sh patterns are mobile code execution. | #7 |
| SC-28 — Protection of Information at Rest | System & Communications Protection | Secrets in image layers are unprotected at rest. | #11, #14 |
| SR-3 — Supply Chain Controls and Processes | Supply Chain Risk | Trusted base images, trusted package registries. | #1, #7, #9, #10, #13 |
| SR-4 — Provenance | Supply Chain Risk | Knowing where an image came from (digest + signed registry). | #9, #13 |
| SR-5 — Acquisition Strategies, Tools, Methods | Supply Chain Risk | Approved sources for images and packages. | #10, #13 |
| SR-6 — Supplier Assessments and Reviews | Supply Chain Risk | The supplier behind the base image / package registry has been vetted. | #10, #13 |
| SR-9 — Tamper Resistance and Detection | Supply Chain Risk | Digest mismatch reveals tampering. | #9 |
| SR-10 — Inspection of Systems or Components | Supply Chain Risk | Scanning + manifest inspection of pinned images. | #9 |
| SR-11 — Component Authenticity | Supply Chain Risk | Digest + signature prove authenticity. | #1, #9, #10, #13 |
| SA-15 — Development Process, Standards, Tools | System & Services Acquisition | Build-time secret handling and tooling. | #11 |
A finding may cite additional controls in its Refs: line — this table covers the ones that recur.
gcr.io/distroless/*) and FROM scratch (for statically compiled binaries) are acceptable peers — see Rule #13 for the approved-registries allow-list.apt/apk/dnf/pip/npm/gem/cargo/go install, or copied in):
gcc, g++, clang, make, cmake, autoconf, automake, libtool, pkg-config, meson, ninja, bazel, sbt, maven, gradle, cargo (the build subcommand, not just the binary), go build toolchain, rustc.gdb, lldb, strace, ltrace, perf, valgrind, tcpdump.*-dev, *-devel, build-essential, linux-headers-*, kernel-devel.pip / pip3 (when no install step needs them), npm / yarn / pnpm (in a runtime image), cargo / rustup, gem, bundle, mvn, gradle, apt-get / apk / dnf themselves remaining in the final stage when no further installs occur..git/ directories copied into the final stage (these belong in the builder stage only).FROM scratch, gcr.io/distroless/static, or cgr.dev/chainguard/static as the final stage — no userland at all.USER directive usage with a UID > 0 in the final stage.USER — relying on a base image's default nonroot is fragile (a base-image change can silently regress to root).USER appuser:appuser or USER 65532:65532 (the conventional nonroot UID).USER root or USER 0 in the final stage (acceptable in the builder stage when necessary for installation).docker run --privileged) — flag any documentation, docker-compose.yml, or Kubernetes manifest in the repo that sets it.LABEL declarations that signal privileged intent (LABEL com.example.privileged="true").--cap-drop=ALL --cap-add=NET_BIND_SERVICE (or equivalent).--read-only rootfs with explicit tmpfs for /tmp and any required writable paths.--security-opt=no-new-privileges:true.Two related problems: (a) shell scripts shipped into the image as the entrypoint, and (b) shell-form ENTRYPOINT / CMD instructions that implicitly spawn /bin/sh -c.
(a) Shell scripts as entrypoints
ENTRYPOINT / CMD that points at a .sh file copied into the image (ENTRYPOINT ["/entrypoint.sh"], CMD ["./run.sh"], etc.).COPY *.sh or ADD *.sh paired with execution at container start.ENTRYPOINT ["python", "-m", "myapp"], ENTRYPOINT ["node", "server.js"], ENTRYPOINT ["./myapp"] for a static binary). Shell scripts pull in a shell and its dependencies, bloat the image, and create signal-handling problems at PID 1.(b) Shell-form vs exec-form
ENTRYPOINT some_command arg1 arg2 (shell form — string, no JSON array).CMD some_command arg1 arg2 (shell form).ENTRYPOINT ["some_command", "arg1", "arg2"].Why exec form matters:
/bin/sh -c "some_command arg1 arg2", which requires /bin/sh to exist in the image (fights Rule #2's minimal-image goal — FROM scratch and most distroless images don't have a shell).SIGTERM, SIGINT), and typically does not forward them to the child. Container takes 10s to die instead of exiting cleanly on docker stop.Exemption: If a wrapper is genuinely required (init-style supervision, signal proxying), use tini or dumb-init as PID 1 rather than a bash script — ENTRYPOINT ["/sbin/tini", "--", "myapp"].
supervisord as the entrypoint, & backgrounded processes in a shell-form entrypoint, init systems (see Rule #12), wrapper scripts that fork multiple long-running daemons.tini or dumb-init as PID 1 — these are not multi-process supervisors.RUN curl ... | sh, RUN wget ... -O - | bash, RUN curl ... | python — these are arbitrary remote code execution at build time and bypass every scanner.RUN curl/RUN wget fetching arbitrary tarballs/binaries from non-allow-listed URLs (anything outside the org's package mirror — see Rule #10).--network=none for stages that should be hermetic (no internet, packages must come from explicit COPY or earlier-stage outputs). This is a SLSA Build L3 requirement.curl, wget, nc, nmap, dig, ssh-client when no application code calls them — these expand the post-exploitation toolkit available to an attacker who lands inside the container.curl | sh is mobile code execution) · SSDF PW 4.4 (Reuse Existing, Well-Secured Software) · SLSA Build L3 (Hermetic, Reproducible Builds) · CIS Docker Benchmark 4.5.Every FROM instruction must reference its base image by an immutable @sha256:<digest> digest, not by a floating tag. This rule applies uniformly across runtimes — language ecosystem does not change the requirement.
Detection rules:
FROM <image>:<tag> reference that lacks @sha256:<64 hex chars>.:latest, :latest-dev, :3, :3.13, :20, :1.22, :21-jdk, :1.75-slim are all violations on their own — they are mutable upstream.FROM scratch is exempt (no image to pin).FROM <alias> referencing a prior AS <alias> build stage is exempt (the alias resolves to an already-pinned image earlier in the file).--platform=... prefix does not change the rule; the image reference still must include @sha256:....Runtime coverage — report violations identically for any of these (non-exhaustive):
| Runtime | Common base images to check |
|---|---|
| Python | python, cgr.dev/chainguard/python, python-slim |
| Node.js | node, cgr.dev/chainguard/node, node-alpine |
| Go | golang, cgr.dev/chainguard/go, cgr.dev/chainguard/static |
| Rust | rust, cgr.dev/chainguard/rust, rust-slim |
| Java / JVM | eclipse-temurin, openjdk, amazoncorretto, cgr.dev/chainguard/jdk, cgr.dev/chainguard/jre |
| Ruby | ruby, cgr.dev/chainguard/ruby |
| .NET | mcr.microsoft.com/dotnet/sdk, mcr.microsoft.com/dotnet/runtime, cgr.dev/chainguard/dotnet-runtime |
| Generic / distroless | alpine, debian, ubuntu, cgr.dev/chainguard/wolfi-base, gcr.io/distroless/* |
Why: Tags are mutable; the image bytes behind python:3.13-slim today are not the bytes behind it next week. Digest pinning gives reproducible builds, makes supply-chain attacks visible (a different digest = a different image), and is required for meaningful SBOM and provenance attestation.
Reporting format: When a violation is found, output:
FROM line and line number.FROM <image>@sha256:<digest> — and instructions to obtain the digest with docker pull <image>:<tag> && docker inspect --format='{{index .RepoDigests 0}}' <image>:<tag> (or crane digest <image>:<tag> / regctl image digest <image>:<tag>).Severity: MEDIUM by default; HIGH for production / published images.
Packages installed during docker build must be pulled from a known, controlled internal registry — never from a public open-source registry directly. Public registries (PyPI, npm, crates.io, Maven Central, RubyGems, NuGet.org, the public Go module proxy, default apt/apk mirrors) are routinely abused for dependency-confusion, typosquatting, account-takeover, and post-install malware. An internal proxy (Artifactory, Nexus, AWS CodeArtifact, GCP Artifact Registry, Azure Artifacts, GitHub Packages, or a Verdaccio / devpi / Athens / Sonatype mirror) provides quarantine, vetting, audit logging, and CVE blocking.
Detection rules:
Flag any RUN line that invokes a package installer without evidence that it has been redirected to an internal registry. Evidence of redirection can be any one of:
--index-url, --extra-index-url, --registry, -i, --repository, GOPROXY=..., --source, -s.ENV (or ARG exposed as env) set earlier in the same stage with one of the recognized variables below..npmrc, pip.conf, .cargo/config.toml, nuget.config, ~/.gemrc, settings.xml, gradle.properties).If none of those are present, the installer is hitting the upstream public default → violation.
Per-runtime detection map:
| Runtime | Installer commands to flag | Acceptable redirection signals |
|---|---|---|
| Python | pip install, pip3 install, python -m pip install, poetry install, poetry add, uv pip install, uv sync, pipenv install, conda install | --index-url=... / -i ..., PIP_INDEX_URL, PIP_EXTRA_INDEX_URL, UV_INDEX_URL, POETRY_REPOSITORIES_*_URL, COPY of pip.conf / pyproject.toml with [[tool.poetry.source]] |
| Node.js | npm install, npm ci, npm i, yarn install, yarn add, pnpm install, pnpm add | --registry=..., NPM_CONFIG_REGISTRY, YARN_NPM_REGISTRY_SERVER, COPY of .npmrc / .yarnrc.yml |
| Go | go build, go get, go install, go mod download, go mod tidy | GOPROXY=<internal>, GONOSUMCHECK=off only with internal GOSUMDB, COPY of go.env |
| Rust | cargo build, cargo install, cargo fetch, cargo update | COPY of .cargo/config.toml with [source.crates-io] replace-with = "internal", CARGO_REGISTRIES_*_INDEX env, --registry <name> |
| Java / JVM | mvn install, mvn package, mvn dependency:resolve, ./gradlew build, ./gradlew dependencies, sbt update | COPY of settings.xml with <mirrors>, MAVEN_OPTS pointing at internal, gradle.properties with internal repositories, init.gradle mirror |
| Ruby | gem install, bundle install, bundle update | --source <internal>, BUNDLE_MIRROR__*, COPY of .gemrc / .bundle/config |
| .NET | dotnet restore, dotnet add package, dotnet build, nuget install, nuget restore | --source <internal>, -s <internal>, COPY of nuget.config with internal <add key="..." value="..."/> |
| OS packages (apt/apk/dnf/yum) | apt-get install, apt install, apk add, dnf install, yum install, microdnf install, zypper install | COPY of sources.list / /etc/apt/sources.list.d/*.list / /etc/apk/repositories / *.repo pointing at internal mirror before the install |
Exemptions:
RUN lines that install only from a path or local file (pip install ./vendor/wheel.whl, npm install ./packages/foo.tgz, dpkg -i ./*.deb) — no registry contacted.--network=none); flag as INFO instead of MEDIUM in that case.Reporting format:
RUN line and line number.pip install, npm ci).pypi.org, registry.npmjs.org, crates.io, proxy.golang.org, repo.maven.apache.org, rubygems.org, api.nuget.org).# Preferred: ship config, keep the install command unchanged
COPY .npmrc /root/.npmrc # contains: registry=https://npm.internal.example.com/
RUN npm ci
# Alternative: flag the install directly
RUN pip install --index-url https://pypi.internal.example.com/simple/ -r requirements.txt
Severity: HIGH for production / published images (supply-chain risk is the single largest attack vector against container builds). MEDIUM for ephemeral / local test images.
COPY'd in stage 1 and "deleted" in stage 2 of a single-stage build is still recoverable from the earlier layer; only a fresh stage that never received the secret is clean.Detection rules — flag any of the following:
ENV lines whose value matches a secret pattern:
*_KEY, *_SECRET, *_TOKEN, *_PASSWORD, *_PASSWD, *_PWD, *_CREDENTIALS, *_API_KEY, *_PRIVATE_KEY.AKIA[0-9A-Z]{16}), AWS secret access key shape (40 base64 chars), GitHub PAT (ghp_, gho_, ghs_, github_pat_), Slack tokens (xox[baprs]-), JWT shape (eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\..*), Stripe keys (sk_live_, pk_live_), Google API key shape (AIza[0-9A-Za-z\-_]{35}), generic 32+ char hex / base64 high-entropy strings.ARG declarations used to bake a secret value into the final image (ARG GITHUB_TOKEN followed by RUN ... $GITHUB_TOKEN ... in the same stage without BuildKit secret mount — the value persists in build history).COPY / ADD of credential files:
.env, .env.* (except .env.example, .env.template).id_rsa, id_ed25519, id_ecdsa, *.pem, *.key, *.p12, *.pfx, *.jks..aws/credentials, .aws/config, gcp-*.json (service-account JSON shape), azure-credentials*, *.kubeconfig, kubeconfig.*-key.pem, private/*.pem.RUN lines containing inline credentials:
curl -H "Authorization: Bearer ey...", curl -u user:password.git clone https://<user>:<token>@github.com/....wget --header="X-API-Key: ...".echo "<token>" | docker login --password-stdin followed by leftover env.LABEL values containing secret-shaped strings.The fix — BuildKit secret mounts:
# syntax=docker/dockerfile:1.7
FROM cgr.dev/chainguard/python@sha256:...
RUN --mount=type=secret,id=pip_token \
pip install --extra-index-url https://$(cat /run/secrets/pip_token)@pypi.internal.example.com/simple/ -r requirements.txt
Build with: docker build --secret id=pip_token,src=$HOME/.pip-token . — the secret is mounted only for that RUN and never written to any layer.
Exemptions:
ca-certificates, public root CA bundles, *.crt without matching *.key) — these are meant to be public..env.example, .env.template, *.env.sample) — pattern-match the suffix.tests/ directories explicitly marked as fake — but still warn (INFO level) since they create habits.Runtime guidance (recommendation, not a Dockerfile violation): Even production credentials should come from workload-identity systems at runtime (IRSA on AWS, Workload Identity on GCP, Managed Identity on Azure, SPIFFE/SPIRE for hybrid) — not baked, not mounted from disk, not in env vars set by an orchestrator.
Severity: HIGH (any production-shaped secret); MEDIUM (test fixtures, low-value tokens).
Production containers run a single application process. They are not VMs. They do not need remote shell access, an init system, or pluggable authentication. Each of these adds a meaningful attack surface and a non-zero footprint, contradicts Rule #6 (single process), and indicates the image is being treated as a long-lived host instead of an immutable artifact.
Detection rules — flag any of the following in the final stage:
openssh-server, openssh-sftp-server, dropbear, ssh-server./usr/sbin/sshd, /usr/bin/dropbear./etc/ssh/sshd_config, /etc/dropbear/.EXPOSE 22 paired with anything that runs sshd.systemd, systemd-* packages, /usr/lib/systemd, /usr/bin/systemctl present.sysvinit-core, openrc, runit, s6 (when used as a full init, not as a tini-style PID 1).supervisord / supervisor (the package, not just supervisord-style logging in an app).libpam-*, pam-*, libpam0g, libpam-modules./etc/pam.d/, /etc/pam.conf.libpam.so (when no human will ever authenticate to this image).Permitted with justification (warn but don't block):
openssh-client, /usr/bin/ssh) — occasionally legitimate for outbound scp/sftp to fetch artifacts. Warn (INFO) and recommend reviewing whether the call belongs in CI/CD instead.tini / dumb-init as PID 1 — explicitly not an init system in the multi-process sense; this is a signal-forwarding shim and is encouraged by Rule #5.The fix:
Remove the package from the install line, or move it to the builder stage if used at build time only.
For "I need to debug a running container" — use kubectl debug / kubectl exec / docker exec, ephemeral debug containers, or sidecar debug containers, not a persistent sshd.
For multi-process needs — split into multiple containers (separate pods/services), not multiple processes in one container.
Maps to: CSF 2.0 PR.AA-05, PR.PS-05, PR.IR-01 (least-privilege access permissions, prevent unauthorized software, infrastructure protection from unauthorized logical access) · NIST 800-190 §4.5 (Use of untrusted images / minimization) · NIST 800-53 CM-7 (Least Functionality — these components are not required for the container's mission), AC-6 (Least Privilege — no interactive admin path), AC-17 (Remote Access — removed at the image level), CM-7(1) (Periodic review and removal of unnecessary functions) · CIS Docker Benchmark 4.5 (Do not install unnecessary packages) · NSA/CISA Kubernetes Hardening Guide (single-purpose containers).
Severity: HIGH (SSH server, systemd in production); MEDIUM (PAM, supervisord); INFO (SSH client).
The base image is the largest single contributor to a container's attack surface and patch burden. It must come from a registry and distribution that the organization explicitly trusts and has procurement/support for. DockerHub library/* images, arbitrary community pushes, and general-purpose OS bases designed for hardware/VMs all fail this test.
Detection rules — flag any FROM matching the following:
docker.io/library/...):
FROM alpine, FROM debian, FROM ubuntu, FROM centos, FROM rockylinux, FROM almalinux, FROM fedora, FROM amazonlinux, FROM python, FROM node, FROM golang, FROM rust, FROM eclipse-temurin, FROM ruby, etc. — all DockerHub.FROM docker.io/..., FROM index.docker.io/..., FROM registry.hub.docker.com/....alpine, debian, ubuntu, centos, rockylinux, almalinux, fedora, amazonlinux, opensuse/leap — these are designed for hardware/VMs and inherit dependency graphs (OpenSSL in the base, PAM, systemd hooks) that bloat container images and aren't purpose-built for the container model.Approved registries (allow-list — adjust per organization):
cgr.dev/chainguard/*, cgr.dev/chainguard-private/*.gcr.io/distroless/*.registry.access.redhat.com/ubi*, registry.redhat.io/ubi*.mcr.microsoft.com/dotnet/*.<your-registry>.example.com/*, <account>.dkr.ecr.<region>.amazonaws.com/*, <region>-docker.pkg.dev/<project>/*, <acr-name>.azurecr.io/*.FROM scratch — always allowed (no base).Recommended replacement matrix:
| Common public base | Approved replacement |
|---|---|
python:* (DockerHub) | cgr.dev/chainguard/python |
node:* | cgr.dev/chainguard/node or gcr.io/distroless/nodejs* |
golang:* → final stage | FROM scratch (for static binaries) or cgr.dev/chainguard/static |
rust:* → final stage | FROM scratch or cgr.dev/chainguard/static |
eclipse-temurin:*-jre | cgr.dev/chainguard/jre or gcr.io/distroless/java* |
ruby:* | cgr.dev/chainguard/ruby |
alpine | cgr.dev/chainguard/wolfi-base (purpose-built peer to Alpine) |
debian / ubuntu | registry.access.redhat.com/ubi9-minimal or cgr.dev/chainguard/wolfi-base |
Reporting format:
FROM line and line number.@sha256:....Configuration: The approved-registry allow-list and per-runtime replacement matrix should be configurable per organization (e.g., secure-container-review.config.yaml). The defaults reflect a "no commercial-vendor commitment" stance; orgs with RHEL subscriptions can promote registry.access.redhat.com/* higher, etc.
Severity: HIGH for production / regulated images; MEDIUM for internal tooling.
Workloads subject to FIPS 140-2/140-3 requirements (FedRAMP, DoD, parts of HIPAA, parts of PCI in regulated geographies, contracts that incorporate FIPS by reference) must use a base image whose cryptographic libraries are FIPS-validated. Non-FIPS bases ship OpenSSL builds whose validation does not apply, which silently breaks compliance.
Detection rules (conditional): Active only when the user or configuration declares a FIPS-required context. Signals that activate the check:
secure-container-review.config.yaml: requireFips: true).LABEL declaring compliance scope:
LABEL compliance.fips="required" or LABEL org.opencontainers.image.compliance="fips-140-3".LABEL fedramp.scope="moderate" / "high" (FedRAMP implies FIPS)..fips-required, or compliance.yaml with fips: required).When active, require the base image to be a FIPS variant. Detection:
-fips, -fips140, fips-, or be on the FIPS allow-list:
cgr.dev/chainguard/*-fips (e.g., cgr.dev/chainguard/python-fips, cgr.dev/chainguard/jre-fips, cgr.dev/chainguard/go-fips).registry.access.redhat.com/ubi9/ubi-minimal with the MODE=fips boot configuration documented in LABEL, plus FIPS-validated OpenSSL.mcr.microsoft.com/dotnet/* variants documented as FIPS-mode.FROM that's clearly non-FIPS (*:latest, *:slim, *-dev without -fips) when FIPS context is active.Additional FIPS hygiene checks when active:
ENV OPENSSL_FIPS=0, RUN ... --disable-fips, golang GODEBUG=fips140=off.libsodium without FIPS build, custom openssl builds from source without enable-fips).LABEL so downstream auditors can confirm without rebuilding.Reporting format:
GOFIPS=1, OpenSSL FIPS provider loaded).Severity when active: HIGH (FIPS is a binary compliance state — non-compliant images fail audits). INFO when context not declared.
For each violation, the report must include a Refs: line that names the specific control identifiers the finding maps to. This turns the output from "advice" into "audit-aligned advice" that downstream auditors, GRC teams, and FedRAMP/SSDF assessors can trace back to their own control catalogs.
Required citation sources (cite all that apply):
On NIST CSF 2.0 specifically: CSF is the outcome-oriented framework most boards and risk committees read; 800-53 is the prescriptive control catalog auditors map to. Citing both makes findings legible to both audiences. The CSF 2.0 PR.PS (Platform Security) function is new in the 2.0 release (Feb 2024) and is where most container-image controls land; older mappings to CSF 1.1 used PR.IP and PR.DS — if a downstream audience is still on CSF 1.1, fall back to PR.IP-01 (baseline config), PR.IP-03 (config change control), PR.DS-06 (integrity).
Required output shape for each finding:
[SEVERITY] <Short rule name>
Location: <file>:<line> (or <stage>/<line>)
Detected: <the exact text or pattern that matched>
Why: <one-line rationale>
Fix: <concrete remediation — code snippet preferred>
Refs: <NIST 800-190 §X.Y> | <NIST 800-53 control IDs> | <SSDF practice IDs> | <CIS Benchmark section> | <other>
Example:
[HIGH] Public package registry used (PyPI default)
Location: Dockerfile:6
Detected: RUN pip install --no-cache-dir -r requirements.txt
Why: pip with no --index-url and no pip.conf COPY'd in — resolves to pypi.org.
Public registries are routinely abused for dependency confusion and typosquatting.
Fix: COPY pip.conf /etc/pip.conf # contains: index-url = https://pypi.internal.example.com/simple/
RUN pip install --no-cache-dir -r requirements.txt
Refs: NIST CSF 2.0 GV.SC-05, GV.SC-07, PR.PS-06 | NIST 800-190 §4.5 |
NIST 800-53 SR-3, SR-5, SR-11 | SSDF PW 4.1, PO 1.1 |
FedRAMP Container Scanning Reqs §3
Roll-up at the top of every report:
Text-based testing using SKILL prompts
plugin.json - Plugin manifest for Claude marketplace marketplace.json - Marketplace entry for plugin discovery
Use Context7 for:
Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub robgil/claude-security-marketplace --plugin secure-container-review