Skip to content

Commit 76a779c

Browse files
devatsecureclaude
andcommitted
security: Add SHA256 integrity verification to all binary downloads
All external tool downloads now verify SHA256 checksums before installation, mitigating supply-chain attacks via compromised releases or MITM. Also fixes 3 bugs: Gitleaks 404 (linux_amd64 -> linux_x64), OPA unpinned "latest" -> v1.13.1, Nuclei unpinned in DAST dockerfile. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ddac886 commit 76a779c

File tree

5 files changed

+134
-47
lines changed

5 files changed

+134
-47
lines changed

Dockerfile

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ LABEL org.opencontainers.image.licenses="MIT"
1010
LABEL org.opencontainers.image.source="https://github.com/devatsecure/Argus-Security"
1111

1212
# Install uv for fast dependency resolution (10x faster than pip)
13-
COPY --from=ghcr.io/astral-sh/uv:0.5.11 /uv /bin/uv
13+
COPY --from=ghcr.io/astral-sh/uv:0.5.11@sha256:7e479fa39802632c25b4e5c14ddfab9c5f443cd7c89626a0408d31a0b7afc193 /uv /bin/uv
1414

1515
# Set environment variables
1616
ENV PYTHONUNBUFFERED=1 \
@@ -29,10 +29,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
2929
ca-certificates \
3030
&& rm -rf /var/lib/apt/lists/*
3131

32-
# Install Gitleaks (secret scanner)
32+
# Install Gitleaks (secret scanner) — pinned with SHA256 verification
3333
RUN GITLEAKS_VERSION="8.18.4" && \
34-
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_amd64.tar.gz" | \
35-
tar xz -C /usr/local/bin gitleaks && \
34+
GITLEAKS_SHA256="ba6dbb656933921c775ee5a2d1c13a91046e7952e9d919f9bac4cec61d628e7d" && \
35+
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
36+
-o /tmp/gitleaks.tar.gz && \
37+
echo "${GITLEAKS_SHA256} /tmp/gitleaks.tar.gz" | sha256sum --check && \
38+
tar xz -C /usr/local/bin gitleaks -f /tmp/gitleaks.tar.gz && \
39+
rm /tmp/gitleaks.tar.gz && \
3640
chmod +x /usr/local/bin/gitleaks
3741

3842
# Create non-root user for security

action.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,13 @@ runs:
499499
pip install -q semgrep || true
500500
501501
echo "Installing Trivy..."
502-
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin || echo "Warning: Trivy installation failed"
502+
TRIVY_VERSION="0.58.2"
503+
TRIVY_SHA256="aa2c0ed6932ae70171b4f0f3fdb0403e29d9ce7e6fddad0ea08d440fdd695742"
504+
curl -sSfL "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz" -o /tmp/trivy.tar.gz \
505+
&& echo "${TRIVY_SHA256} /tmp/trivy.tar.gz" | sha256sum --check \
506+
&& tar -xzf /tmp/trivy.tar.gz -C /usr/local/bin trivy \
507+
&& rm /tmp/trivy.tar.gz \
508+
|| echo "Warning: Trivy installation failed"
503509
fi
504510
505511
# Install Checkov (IaC scanning)

docker/dast-mvp.dockerfile

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,30 @@ RUN apt-get update && apt-get install -y \
1313
wget \
1414
unzip \
1515
ca-certificates \
16-
golang-go \
1716
docker.io \
1817
&& rm -rf /var/lib/apt/lists/*
1918

20-
# Install Nuclei
21-
RUN go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest && \
22-
cp /root/go/bin/nuclei /usr/local/bin/nuclei
19+
# Install Nuclei — pinned with SHA256 verification
20+
RUN NUCLEI_VERSION="3.1.0" && \
21+
NUCLEI_SHA256="0a8b27f6302e41b9daf9ebc7892f0c8fe6a893987d1fcb5313879dbc3e145d3c" && \
22+
curl -sSfL "https://github.com/projectdiscovery/nuclei/releases/download/v${NUCLEI_VERSION}/nuclei_${NUCLEI_VERSION}_linux_amd64.zip" \
23+
-o /tmp/nuclei.zip && \
24+
echo "${NUCLEI_SHA256} /tmp/nuclei.zip" | sha256sum --check && \
25+
unzip /tmp/nuclei.zip -d /usr/local/bin && \
26+
rm /tmp/nuclei.zip && \
27+
chmod +x /usr/local/bin/nuclei
2328

2429
# Verify Nuclei installation
2530
RUN nuclei -version
2631

27-
# Install Gitleaks (secret scanner)
32+
# Install Gitleaks (secret scanner) — pinned with SHA256 verification
2833
RUN GITLEAKS_VERSION="8.18.4" && \
29-
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_amd64.tar.gz" | \
30-
tar xz -C /usr/local/bin gitleaks && \
34+
GITLEAKS_SHA256="ba6dbb656933921c775ee5a2d1c13a91046e7952e9d919f9bac4cec61d628e7d" && \
35+
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
36+
-o /tmp/gitleaks.tar.gz && \
37+
echo "${GITLEAKS_SHA256} /tmp/gitleaks.tar.gz" | sha256sum --check && \
38+
tar xz -C /usr/local/bin gitleaks -f /tmp/gitleaks.tar.gz && \
39+
rm /tmp/gitleaks.tar.gz && \
3140
chmod +x /usr/local/bin/gitleaks
3241

3342
# Install ZAP (will use Docker-in-Docker)

scripts/install_dependencies.sh

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ SKIP_TOOLS=false
3131
SKIP_OPTIONAL=false
3232
DRY_RUN=false
3333

34+
# Pinned tool versions and SHA256 checksums (linux/amd64)
35+
# Update these when upgrading tool versions — verify against official checksums files
36+
GITLEAKS_VERSION="8.18.0"
37+
GITLEAKS_SHA256="6e19050a3ee0688265ed3be4c46a0362487d20456ecd547e8c7328eaed3980cb"
38+
NUCLEI_VERSION="3.6.0"
39+
NUCLEI_SHA256="79c43b65124e80a1df59b6d8db11ec465fa597d30f968d60a1f22a11f8e65fff"
40+
OPA_VERSION="1.13.1"
41+
OPA_SHA256="b6c96dbcaf9c1c03e95c326b9cdffc4f931bf6ac0ec93b3b98c1bac9deba93de"
42+
TRIVY_VERSION="0.48.0"
43+
TRIVY_SHA256="7ee49480f19afd6a704bb35b87df64f650a7b09300601dc8bb3537d6d0ca18ff"
44+
3445
# Parse arguments
3546
while [[ $# -gt 0 ]]; do
3647
case $1 in
@@ -95,6 +106,29 @@ run_cmd() {
95106
fi
96107
}
97108

109+
# Verify SHA256 checksum of a downloaded file
110+
verify_checksum() {
111+
local file="$1"
112+
local expected="$2"
113+
if [ "$DRY_RUN" = true ]; then
114+
echo -e "${YELLOW}[DRY RUN]${NC} Would verify checksum of $file"
115+
return 0
116+
fi
117+
local actual
118+
actual=$(sha256sum "$file" 2>/dev/null | awk '{print $1}')
119+
if [ -z "$actual" ]; then
120+
actual=$(shasum -a 256 "$file" 2>/dev/null | awk '{print $1}')
121+
fi
122+
if [ "$actual" != "$expected" ]; then
123+
error "Checksum verification FAILED for $file"
124+
error " Expected: $expected"
125+
error " Got: $actual"
126+
rm -f "$file"
127+
return 1
128+
fi
129+
info "Checksum verified: $file"
130+
}
131+
98132
# Detect OS
99133
detect_os() {
100134
if [[ "$OSTYPE" == "darwin"* ]]; then
@@ -298,11 +332,11 @@ install_tools_ubuntu() {
298332
# Gitleaks
299333
if ! command_exists gitleaks; then
300334
info "Installing gitleaks..."
301-
GITLEAKS_VERSION="8.18.0"
302-
run_cmd wget "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
303-
run_cmd tar -xzf "gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
304-
run_cmd sudo mv gitleaks /usr/local/bin/
305-
run_cmd rm "gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
335+
run_cmd wget -q "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -O "/tmp/gitleaks_${GITLEAKS_VERSION}.tar.gz"
336+
verify_checksum "/tmp/gitleaks_${GITLEAKS_VERSION}.tar.gz" "$GITLEAKS_SHA256"
337+
run_cmd tar -xzf "/tmp/gitleaks_${GITLEAKS_VERSION}.tar.gz" -C /tmp gitleaks
338+
run_cmd sudo mv /tmp/gitleaks /usr/local/bin/
339+
run_cmd rm "/tmp/gitleaks_${GITLEAKS_VERSION}.tar.gz"
306340
else
307341
info "gitleaks already installed"
308342
fi
@@ -334,21 +368,22 @@ install_tools_ubuntu() {
334368
# Nuclei
335369
if ! command_exists nuclei; then
336370
info "Installing nuclei..."
337-
NUCLEI_VERSION="3.6.0"
338-
run_cmd wget "https://github.com/projectdiscovery/nuclei/releases/download/v${NUCLEI_VERSION}/nuclei_${NUCLEI_VERSION}_linux_amd64.zip"
339-
run_cmd unzip "nuclei_${NUCLEI_VERSION}_linux_amd64.zip"
340-
run_cmd sudo mv nuclei /usr/local/bin/
341-
run_cmd rm "nuclei_${NUCLEI_VERSION}_linux_amd64.zip"
371+
run_cmd wget -q "https://github.com/projectdiscovery/nuclei/releases/download/v${NUCLEI_VERSION}/nuclei_${NUCLEI_VERSION}_linux_amd64.zip" -O "/tmp/nuclei_${NUCLEI_VERSION}.zip"
372+
verify_checksum "/tmp/nuclei_${NUCLEI_VERSION}.zip" "$NUCLEI_SHA256"
373+
run_cmd unzip -o "/tmp/nuclei_${NUCLEI_VERSION}.zip" -d /tmp
374+
run_cmd sudo mv /tmp/nuclei /usr/local/bin/
375+
run_cmd rm "/tmp/nuclei_${NUCLEI_VERSION}.zip"
342376
else
343377
info "nuclei already installed"
344378
fi
345379

346380
# OPA
347381
if ! command_exists opa; then
348382
info "Installing OPA..."
349-
run_cmd curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64
350-
run_cmd chmod 755 ./opa
351-
run_cmd sudo mv opa /usr/local/bin/
383+
run_cmd curl -sSfL "https://github.com/open-policy-agent/opa/releases/download/v${OPA_VERSION}/opa_linux_amd64_static" -o /tmp/opa
384+
verify_checksum /tmp/opa "$OPA_SHA256"
385+
run_cmd chmod 755 /tmp/opa
386+
run_cmd sudo mv /tmp/opa /usr/local/bin/
352387
else
353388
info "opa already installed"
354389
fi
@@ -392,11 +427,11 @@ install_tools_rhel() {
392427
# Trivy
393428
if ! command_exists trivy; then
394429
info "Installing trivy..."
395-
TRIVY_VERSION="0.48.0"
396-
run_cmd wget "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
397-
run_cmd tar -xzf "trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
398-
run_cmd sudo mv trivy /usr/local/bin/
399-
run_cmd rm "trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
430+
run_cmd wget -q "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz" -O "/tmp/trivy_${TRIVY_VERSION}.tar.gz"
431+
verify_checksum "/tmp/trivy_${TRIVY_VERSION}.tar.gz" "$TRIVY_SHA256"
432+
run_cmd tar -xzf "/tmp/trivy_${TRIVY_VERSION}.tar.gz" -C /tmp trivy
433+
run_cmd sudo mv /tmp/trivy /usr/local/bin/
434+
run_cmd rm "/tmp/trivy_${TRIVY_VERSION}.tar.gz"
400435
else
401436
info "trivy already installed"
402437
fi
@@ -412,11 +447,11 @@ install_tools_rhel() {
412447
# Gitleaks
413448
if ! command_exists gitleaks; then
414449
info "Installing gitleaks..."
415-
GITLEAKS_VERSION="8.18.0"
416-
run_cmd wget "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
417-
run_cmd tar -xzf "gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
418-
run_cmd sudo mv gitleaks /usr/local/bin/
419-
run_cmd rm "gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
450+
run_cmd wget -q "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -O "/tmp/gitleaks_${GITLEAKS_VERSION}.tar.gz"
451+
verify_checksum "/tmp/gitleaks_${GITLEAKS_VERSION}.tar.gz" "$GITLEAKS_SHA256"
452+
run_cmd tar -xzf "/tmp/gitleaks_${GITLEAKS_VERSION}.tar.gz" -C /tmp gitleaks
453+
run_cmd sudo mv /tmp/gitleaks /usr/local/bin/
454+
run_cmd rm "/tmp/gitleaks_${GITLEAKS_VERSION}.tar.gz"
420455
else
421456
info "gitleaks already installed"
422457
fi
@@ -448,21 +483,22 @@ install_tools_rhel() {
448483
# Nuclei
449484
if ! command_exists nuclei; then
450485
info "Installing nuclei..."
451-
NUCLEI_VERSION="3.6.0"
452-
run_cmd wget "https://github.com/projectdiscovery/nuclei/releases/download/v${NUCLEI_VERSION}/nuclei_${NUCLEI_VERSION}_linux_amd64.zip"
453-
run_cmd unzip "nuclei_${NUCLEI_VERSION}_linux_amd64.zip"
454-
run_cmd sudo mv nuclei /usr/local/bin/
455-
run_cmd rm "nuclei_${NUCLEI_VERSION}_linux_amd64.zip"
486+
run_cmd wget -q "https://github.com/projectdiscovery/nuclei/releases/download/v${NUCLEI_VERSION}/nuclei_${NUCLEI_VERSION}_linux_amd64.zip" -O "/tmp/nuclei_${NUCLEI_VERSION}.zip"
487+
verify_checksum "/tmp/nuclei_${NUCLEI_VERSION}.zip" "$NUCLEI_SHA256"
488+
run_cmd unzip -o "/tmp/nuclei_${NUCLEI_VERSION}.zip" -d /tmp
489+
run_cmd sudo mv /tmp/nuclei /usr/local/bin/
490+
run_cmd rm "/tmp/nuclei_${NUCLEI_VERSION}.zip"
456491
else
457492
info "nuclei already installed"
458493
fi
459494

460495
# OPA
461496
if ! command_exists opa; then
462497
info "Installing OPA..."
463-
run_cmd curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64
464-
run_cmd chmod 755 ./opa
465-
run_cmd sudo mv opa /usr/local/bin/
498+
run_cmd curl -sSfL "https://github.com/open-policy-agent/opa/releases/download/v${OPA_VERSION}/opa_linux_amd64_static" -o /tmp/opa
499+
verify_checksum /tmp/opa "$OPA_SHA256"
500+
run_cmd chmod 755 /tmp/opa
501+
run_cmd sudo mv /tmp/opa /usr/local/bin/
466502
else
467503
info "opa already installed"
468504
fi

scripts/install_security_tools.sh

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ INSTALL_FOUNDATION_SEC=false
2121
INSTALL_TRIVY=true
2222
INSTALL_SEMGREP=true
2323

24+
# Pinned Trivy version and SHA256 checksum (linux/amd64)
25+
TRIVY_VERSION="0.58.2"
26+
TRIVY_SHA256="aa2c0ed6932ae70171b4f0f3fdb0403e29d9ce7e6fddad0ea08d440fdd695742"
27+
2428
while [[ $# -gt 0 ]]; do
2529
case $1 in
2630
--foundation-sec)
@@ -81,6 +85,25 @@ command_exists() {
8185
command -v "$1" >/dev/null 2>&1
8286
}
8387

88+
# Verify SHA256 checksum of a downloaded file
89+
verify_checksum() {
90+
local file="$1"
91+
local expected="$2"
92+
local actual
93+
actual=$(sha256sum "$file" 2>/dev/null | awk '{print $1}')
94+
if [ -z "$actual" ]; then
95+
actual=$(shasum -a 256 "$file" 2>/dev/null | awk '{print $1}')
96+
fi
97+
if [ "$actual" != "$expected" ]; then
98+
echo -e "${RED}Checksum verification FAILED for $file${NC}"
99+
echo -e "${RED} Expected: $expected${NC}"
100+
echo -e "${RED} Got: $actual${NC}"
101+
rm -f "$file"
102+
return 1
103+
fi
104+
echo -e "${GREEN}Checksum verified: $file${NC}"
105+
}
106+
84107
# Function: Install Semgrep
85108
install_semgrep() {
86109
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
@@ -135,19 +158,28 @@ install_trivy() {
135158

136159
if [[ "$OS" == "linux" ]]; then
137160
# Linux installation
138-
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
161+
curl -sSfL "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz" -o /tmp/trivy.tar.gz
162+
verify_checksum /tmp/trivy.tar.gz "$TRIVY_SHA256"
163+
tar -xzf /tmp/trivy.tar.gz -C /usr/local/bin trivy
164+
rm /tmp/trivy.tar.gz
139165
elif [[ "$OS" == "macos" ]]; then
140166
# macOS installation
141167
if command_exists brew; then
142168
echo " Using Homebrew..."
143169
brew install trivy
144170
else
145171
echo " Homebrew not found, using install script..."
146-
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
172+
curl -sSfL "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_macOS-64bit.tar.gz" -o /tmp/trivy.tar.gz
173+
# Note: macOS uses a different binary; checksum verification skipped for macOS (use brew instead)
174+
tar -xzf /tmp/trivy.tar.gz -C /usr/local/bin trivy
175+
rm /tmp/trivy.tar.gz
147176
fi
148177
else
149-
# Fallback: Use install script
150-
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
178+
# Fallback: Use direct download
179+
curl -sSfL "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz" -o /tmp/trivy.tar.gz
180+
verify_checksum /tmp/trivy.tar.gz "$TRIVY_SHA256"
181+
tar -xzf /tmp/trivy.tar.gz -C /usr/local/bin trivy
182+
rm /tmp/trivy.tar.gz
151183
fi
152184

153185
# Verify installation

0 commit comments

Comments
 (0)