From ac003ede28c28039c4c0fbc45466e1d3eb3720b5 Mon Sep 17 00:00:00 2001 From: BaaRai <130491490+BaaRai@users.noreply.github.com> Date: Wed, 11 Nov 2026 20:38:33 +0100 Subject: [PATCH] chore(docker): verify tool downloads and pin build inputs Stage the recon binaries in a build-platform "tools" stage and verify each release archive against the checksums file of its own GitHub release (exact asset name, sha256), failing the build when the entry is missing or does not match: nuclei v3.11.1, httpx v1.12.0, subfinder v2.17.0, katana v1.8.0, ffuf v2.3.0, dalfox v3.2.4. sqlmap is cloned at tag 1.9.9 and checked against commit cceda39208b5aad478de2c3f731df4239d9881f6 before .git is removed. The runtime stage copies /out/ and /opt/sqlmap from that stage. Install Node v22.23.4 from the official nodejs.org tarball verified against SHASUMS256.txt instead of piping the NodeSource setup script into bash. Pin @playwright/mcp@0.0.83, @playwright/cli@0.1.22 and playwright@1.64.1 instead of @latest. amd64 and arm64 are mapped explicitly; any other architecture fails the build. dalfox --version no longer ignores failures. Carries over the Dockerfile part of #127 by stevenAthompson. --- Dockerfile | 127 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 37 deletions(-) diff --git a/Dockerfile b/Dockerfile index df949f7..d32ce8f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,51 +43,101 @@ RUN ARTEX_SKIP_FRONTEND=1 \ ARTEX_BUILD_VERSION="${ARTEX_VERSION}" \ bash ./build.sh --target "${TARGETOS:-linux}/${TARGETARCH:-amd64}" -# ---------------------------------------------------------------- runtime --- -FROM python:3.12-slim-bookworm +# ------------------------------------------------------- third-party tools --- +# Web-recon toolbox (drost-community take 1, #100): pinned release binaries, staged +# on the build platform and copied into /usr/local/bin of the runtime image so hunt +# workers can run them directly through their Bash tool. Versions pinned per tool; +# upgrade deliberately. Each archive is verified against the checksums file of its +# own GitHub release (exact asset name, sha256). That file comes from the same +# release channel as the archive, so it catches corrupted or swapped downloads and +# moved tags, not a compromised publisher. sqlmap has no release binaries: it is a +# shallow clone of a pinned tag, checked against the expected commit. +FROM --platform=$BUILDPLATFORM debian:bookworm-slim AS tools ARG TARGETARCH -# Common tools: ripgrep / curl / vim, plus a set of recon staples (add/remove as needed). -# Node 22.x comes from NodeSource: bookworm's apt nodejs is 18, Playwright requires >=20, -# and 20 is end-of-life. 22 matches the CI and release workflows. -RUN apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates ripgrep curl wget vim git jq unzip \ - dnsutils iputils-ping netcat-openbsd inetutils-telnet whois nmap \ - && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ - && apt-get install -y --no-install-recommends nodejs \ - && rm -rf /var/lib/apt/lists/* -# Web-recon toolbox (drost-community take 1, #100): pinned release binaries installed -# into /usr/local/bin so hunt workers can run them directly through their Bash tool. -# Versions pinned per tool; upgrade deliberately. sqlmap is a python checkout (no -# release binaries) symlinked into PATH. ARG NUCLEI_VERSION=v3.11.1 ARG HTTPX_VERSION=v1.12.0 ARG SUBFINDER_VERSION=v2.17.0 ARG KATANA_VERSION=v1.8.0 ARG FFUF_VERSION=v2.3.0 ARG DALFOX_VERSION=v3.2.4 +ARG SQLMAP_VERSION=1.9.9 +ARG SQLMAP_COMMIT=cceda39208b5aad478de2c3f731df4239d9881f6 +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl git unzip \ + && rm -rf /var/lib/apt/lists/* +RUN set -eux; \ + case "${TARGETARCH:-amd64}" in \ + amd64) PD_ARCH=amd64; FFUF_ARCH=amd64; DALFOX_ARCH=x86_64 ;; \ + arm64) PD_ARCH=arm64; FFUF_ARCH=arm64; DALFOX_ARCH=aarch64 ;; \ + *) echo "unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + mkdir -p /out; \ + fetch() { base="$1"; asset="$2"; sums="$3"; name="$4"; \ + rm -rf /tmp/t; mkdir -p /tmp/t/x; \ + curl -fsSL "$base/$asset" -o "/tmp/t/$asset"; \ + curl -fsSL "$base/$sums" -o /tmp/t/sums.txt; \ + want="$(awk -v a="$asset" '$2 == a || $2 == "*" a { print $1 }' /tmp/t/sums.txt)"; \ + if [ -z "$want" ]; then echo "no checksum entry for $asset" >&2; exit 1; fi; \ + got="$(sha256sum "/tmp/t/$asset" | cut -d' ' -f1)"; \ + if [ "$want" != "$got" ]; then echo "checksum mismatch for $asset: want $want got $got" >&2; exit 1; fi; \ + case "$asset" in *.zip) unzip -q "/tmp/t/$asset" -d /tmp/t/x ;; *) tar -xzf "/tmp/t/$asset" -C /tmp/t/x ;; esac; \ + find /tmp/t/x -type f -name "$name" -exec install -m 0755 {} /out/ \; ; \ + [ -x "/out/$name" ] || { echo "$name not found in $asset" >&2; exit 1; }; \ + rm -rf /tmp/t; }; \ + gh="https://github.com"; \ + fetch "$gh/projectdiscovery/nuclei/releases/download/$NUCLEI_VERSION" \ + "nuclei_${NUCLEI_VERSION#v}_linux_${PD_ARCH}.zip" "nuclei_${NUCLEI_VERSION#v}_checksums.txt" nuclei; \ + fetch "$gh/projectdiscovery/httpx/releases/download/$HTTPX_VERSION" \ + "httpx_${HTTPX_VERSION#v}_linux_${PD_ARCH}.zip" "httpx_${HTTPX_VERSION#v}_checksums.txt" httpx; \ + fetch "$gh/projectdiscovery/subfinder/releases/download/$SUBFINDER_VERSION" \ + "subfinder_${SUBFINDER_VERSION#v}_linux_${PD_ARCH}.zip" "subfinder_${SUBFINDER_VERSION#v}_checksums.txt" subfinder; \ + fetch "$gh/projectdiscovery/katana/releases/download/$KATANA_VERSION" \ + "katana_${KATANA_VERSION#v}_linux_${PD_ARCH}.zip" "katana-${KATANA_VERSION#v}-checksums.txt" katana; \ + fetch "$gh/ffuf/ffuf/releases/download/$FFUF_VERSION" \ + "ffuf_${FFUF_VERSION#v}_linux_${FFUF_ARCH}.tar.gz" "ffuf_${FFUF_VERSION#v}_checksums.txt" ffuf; \ + fetch "$gh/hahwul/dalfox/releases/download/$DALFOX_VERSION" \ + "dalfox-${DALFOX_VERSION}-linux-${DALFOX_ARCH}-musl.tar.gz" "dalfox-${DALFOX_VERSION}-linux-${DALFOX_ARCH}-musl.tar.gz.sha256" dalfox; \ + git clone --quiet --depth 1 --branch "$SQLMAP_VERSION" https://github.com/sqlmapproject/sqlmap /opt/sqlmap; \ + commit="$(git -C /opt/sqlmap rev-parse HEAD)"; \ + if [ "$commit" != "$SQLMAP_COMMIT" ]; then echo "sqlmap commit mismatch: want $SQLMAP_COMMIT got $commit" >&2; exit 1; fi; \ + rm -rf /opt/sqlmap/.git + +# ---------------------------------------------------------------- runtime --- +FROM python:3.12-slim-bookworm +ARG TARGETARCH +# Common tools: ripgrep / curl / vim, plus a set of recon staples (add/remove as needed). +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates ripgrep curl wget vim git jq unzip xz-utils \ + dnsutils iputils-ping netcat-openbsd inetutils-telnet whois nmap \ + && rm -rf /var/lib/apt/lists/* +# Node 22 from the official nodejs.org tarball, verified against its SHASUMS256.txt: +# bookworm's apt nodejs is 18, Playwright requires >=20, and 20 is end-of-life. +# 22 matches the CI and release workflows. +ARG NODE_VERSION=22.23.4 +RUN set -eux; \ + case "${TARGETARCH:-amd64}" in \ + amd64) NODE_ARCH=x64 ;; \ + arm64) NODE_ARCH=arm64 ;; \ + *) echo "unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + base="https://nodejs.org/dist/v${NODE_VERSION}"; \ + asset="node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.xz"; \ + curl -fsSL "$base/$asset" -o "/tmp/$asset"; \ + curl -fsSL "$base/SHASUMS256.txt" -o /tmp/SHASUMS256.txt; \ + want="$(awk -v a="$asset" '$2 == a { print $1 }' /tmp/SHASUMS256.txt)"; \ + if [ -z "$want" ]; then echo "no checksum entry for $asset" >&2; exit 1; fi; \ + got="$(sha256sum "/tmp/$asset" | cut -d' ' -f1)"; \ + if [ "$want" != "$got" ]; then echo "checksum mismatch for $asset: want $want got $got" >&2; exit 1; fi; \ + tar -xJf "/tmp/$asset" -C /usr/local --strip-components=1 --no-same-owner; \ + rm -f "/tmp/$asset" /tmp/SHASUMS256.txt; \ + node --version; npm --version +# Pinned, checksum-verified recon binaries and the sqlmap checkout from the tools stage. +COPY --from=tools /out/ /usr/local/bin/ +COPY --from=tools /opt/sqlmap /opt/sqlmap RUN set -eux; \ - base="https://github.com"; \ - pd_fetch() { repo="$1"; ver="$2"; name="$3"; nov="${ver#v}"; \ - curl -fsSL "$base/$repo/releases/download/$ver/${name}_${nov}_linux_${TARGETARCH}.zip" -o /tmp/t.zip \ - && unzip -o -q /tmp/t.zip -d /tmp/td \ - && find /tmp/td -type f -name "$name" -exec install -m 0755 {} /usr/local/bin/ \; \ - && rm -rf /tmp/t.zip /tmp/td; }; \ - case "$TARGETARCH" in amd64) FFUF_ARCH=amd64; DALFOX_ARCH=x86_64;; arm64) FFUF_ARCH=arm64; DALFOX_ARCH=aarch64;; esac; \ - pd_fetch projectdiscovery/nuclei "$NUCLEI_VERSION" nuclei; \ - pd_fetch projectdiscovery/httpx "$HTTPX_VERSION" httpx; \ - pd_fetch projectdiscovery/subfinder "$SUBFINDER_VERSION" subfinder; \ - pd_fetch projectdiscovery/katana "$KATANA_VERSION" katana; \ - tar_fetch() { url="$1"; name="$2"; \ - curl -fsSL "$url" -o /tmp/t.tgz \ - && mkdir -p /tmp/td && tar -xzf /tmp/t.tgz -C /tmp/td \ - && find /tmp/td -type f -name "$name" -exec install -m 0755 {} /usr/local/bin/ \; \ - && rm -rf /tmp/t.tgz /tmp/td; }; \ - tar_fetch "$base/ffuf/ffuf/releases/download/$FFUF_VERSION/ffuf_${FFUF_VERSION#v}_linux_${FFUF_ARCH}.tar.gz" ffuf; \ - tar_fetch "$base/hahwul/dalfox/releases/download/$DALFOX_VERSION/dalfox-${DALFOX_VERSION}-linux-${DALFOX_ARCH}-musl.tar.gz" dalfox; \ - git clone --depth 1 https://github.com/sqlmapproject/sqlmap /opt/sqlmap; \ ln -s /opt/sqlmap/sqlmap.py /usr/local/bin/sqlmap; \ nuclei -version >/dev/null; httpx -version; subfinder -version; katana -version; \ - ffuf -V >/dev/null; dalfox --version >/dev/null 2>&1 || true; sqlmap --version >/dev/null + ffuf -V >/dev/null; dalfox --version >/dev/null; sqlmap --version >/dev/null # bbot recursive recon orchestrator (#117): blacklanternsecurity/bbot, AGPL-3.0 # (same license as ARTEX; standalone CLI dependency, not linked code). Pinned @@ -111,8 +161,11 @@ RUN set -eux; \ # @playwright/cli: provides playwright-cli, verified with --help right after install. # Then install playwright (browser management) and preinstall chromium plus its system # dependencies via --with-deps, so MCP/CLI work on first start inside the container -# without downloading browsers over the network. -RUN npm install -g @playwright/mcp@latest @playwright/cli@latest playwright@latest \ +# without downloading browsers over the network. All three are pinned; upgrade deliberately. +ARG PLAYWRIGHT_MCP_VERSION=0.0.83 +ARG PLAYWRIGHT_CLI_VERSION=0.1.22 +ARG PLAYWRIGHT_VERSION=1.64.1 +RUN npm install -g "@playwright/mcp@${PLAYWRIGHT_MCP_VERSION}" "@playwright/cli@${PLAYWRIGHT_CLI_VERSION}" "playwright@${PLAYWRIGHT_VERSION}" \ && playwright-cli --help \ && playwright install --with-deps chromium \ && rm -rf /var/lib/apt/lists/*