Summary
All six container images used by the gh-aw MCP stack (node:lts-alpine, ghcr.io/github/gh-aw-firewall/agent:0.25.11, ghcr.io/github/gh-aw-firewall/api-proxy:0.25.11, ghcr.io/github/gh-aw-firewall/squid:0.25.11, ghcr.io/github/gh-aw-mcpg:v0.2.11, ghcr.io/github/github-mcp-server:v0.32.0) are pulled by mutable tag with no SHA-256 digest pinning. The node:lts-alpine alias is additionally floating — its content changes whenever the Node.js LTS designation shifts to a new major release, making it non-deterministic independent of any registry compromise. By contrast, the gh-aw documentation already cites action SHA pinning as a defense-in-depth property for GitHub Actions steps but applies no equivalent policy to Docker images.
Affected Area
Pre-agent container supply-chain boundary. Image pulls in download_docker_images.sh occur before the agent process starts, so a compromised image could affect the AWF network enforcement container and the MCP gateway — potentially undermining multiple defense-in-depth layers simultaneously for the full duration of the run.
Reproduction Outline
- Compile any gh-aw pentest workflow that includes the standard MCP image set and inspect the generated lock file's "Download container images" step.
- Confirm none of the six image references contain an
@sha256: suffix.
- Review
actions/setup/sh/download_docker_images.sh: the docker pull --quiet "$image" call uses the tag as-is with no digest extraction or post-pull verification.
- Observe that
node:lts-alpine is a floating alias: when a new Node.js LTS version is designated, the tag silently points to a different image on the next pull.
- For
ghcr.io/github/* version tags: GHCR tags are mutable by default; a registry write could push new content under an existing version tag without detection.
Observed Behavior
download_docker_images.sh pulls all six images by tag only (docker pull --quiet "$image"). No @sha256: digest is appended, no digest is extracted after pull, and no signature verification step runs. The node:lts-alpine floating tag shifts content across LTS generations.
Expected Behavior
All production image references should be pinned to immutable content digests, e.g.:
ghcr.io/github/gh-aw-mcpg:v0.2.11@sha256:<digest>
node:22-alpine@sha256:<digest> (replacing the floating lts-alpine alias)
A CI check should reject any image reference lacking @sha256: in generated lock files.
Security Relevance
A supply-chain compromise of Docker Hub (for node:lts-alpine) or the GitHub GHCR registry (for ghcr.io/github/* images) could inject a malicious MCP container that intercepts tool traffic, manipulates MCP responses, or undermines AWF network enforcement — affecting every workflow run that pulls the compromised image. The node:lts-alpine floating alias additionally creates non-deterministic runtime behavior without any registry compromise. The gh-aw documentation's existing SHA-pinning guidance for Actions steps is not extended to Docker images, so this gap is not framed as an explicit security tradeoff anywhere in published docs.
gh-aw version: v0.65.6
Original finding: https://github.com/githubnext/gh-aw-security/issues/1702
Generated by File Issue · ● 215.7K · ◷
Summary
All six container images used by the gh-aw MCP stack (
node:lts-alpine,ghcr.io/github/gh-aw-firewall/agent:0.25.11,ghcr.io/github/gh-aw-firewall/api-proxy:0.25.11,ghcr.io/github/gh-aw-firewall/squid:0.25.11,ghcr.io/github/gh-aw-mcpg:v0.2.11,ghcr.io/github/github-mcp-server:v0.32.0) are pulled by mutable tag with no SHA-256 digest pinning. Thenode:lts-alpinealias is additionally floating — its content changes whenever the Node.js LTS designation shifts to a new major release, making it non-deterministic independent of any registry compromise. By contrast, the gh-aw documentation already cites action SHA pinning as a defense-in-depth property for GitHub Actions steps but applies no equivalent policy to Docker images.Affected Area
Pre-agent container supply-chain boundary. Image pulls in
download_docker_images.shoccur before the agent process starts, so a compromised image could affect the AWF network enforcement container and the MCP gateway — potentially undermining multiple defense-in-depth layers simultaneously for the full duration of the run.Reproduction Outline
@sha256:suffix.actions/setup/sh/download_docker_images.sh: thedocker pull --quiet "$image"call uses the tag as-is with no digest extraction or post-pull verification.node:lts-alpineis a floating alias: when a new Node.js LTS version is designated, the tag silently points to a different image on the next pull.ghcr.io/github/*version tags: GHCR tags are mutable by default; a registry write could push new content under an existing version tag without detection.Observed Behavior
download_docker_images.shpulls all six images by tag only (docker pull --quiet "$image"). No@sha256:digest is appended, no digest is extracted after pull, and no signature verification step runs. Thenode:lts-alpinefloating tag shifts content across LTS generations.Expected Behavior
All production image references should be pinned to immutable content digests, e.g.:
ghcr.io/github/gh-aw-mcpg:v0.2.11@sha256:<digest>node:22-alpine@sha256:<digest>(replacing the floatinglts-alpinealias)A CI check should reject any image reference lacking
@sha256:in generated lock files.Security Relevance
A supply-chain compromise of Docker Hub (for
node:lts-alpine) or the GitHub GHCR registry (forghcr.io/github/*images) could inject a malicious MCP container that intercepts tool traffic, manipulates MCP responses, or undermines AWF network enforcement — affecting every workflow run that pulls the compromised image. Thenode:lts-alpinefloating alias additionally creates non-deterministic runtime behavior without any registry compromise. The gh-aw documentation's existing SHA-pinning guidance for Actions steps is not extended to Docker images, so this gap is not framed as an explicit security tradeoff anywhere in published docs.gh-aw version: v0.65.6
Original finding: https://github.com/githubnext/gh-aw-security/issues/1702