fix(ci): harden WorkflowTemplate against template injection
commit-sha (from the untrusted Gitea webhook body.after) was substituted
INLINE into shell scripts via {{workflow.parameters.commit-sha}} in all
three git-clone/decide-mode steps -> a malicious payload could inject shell
on a cluster-privileged pod. Now passed via ENV + hex-validated before use
(the build-image template's pattern), and mode is allowlist-checked. Closes
the background security review's Orchestrator Template Injection finding.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -51,32 +51,38 @@ spec:
|
||||
container:
|
||||
image: alpine/git:latest
|
||||
command: [/bin/sh, -c]
|
||||
# SECURITY: commit-sha/mode arrive via ENV (not inline {{...}} substitution) so an untrusted webhook
|
||||
# payload cannot inject shell. commit-sha is validated hex before use; mode is checked against an allowlist.
|
||||
env:
|
||||
- { name: COMMIT_SHA, value: "{{workflow.parameters.commit-sha}}" }
|
||||
- { name: MODE, value: "{{workflow.parameters.mode}}" }
|
||||
args:
|
||||
- |
|
||||
set -e
|
||||
case "$COMMIT_SHA" in *[!0-9a-fA-F]*|"") echo "refusing non-hex commit-sha" >&2; exit 1 ;; esac
|
||||
case "$MODE" in auto|build|deploy) : ;; *) echo "refusing unknown mode: $MODE" >&2; exit 1 ;; esac
|
||||
mkdir -p /root/.ssh
|
||||
cp /etc/git-ssh/ssh-privatekey /root/.ssh/id_ed25519
|
||||
chmod 600 /root/.ssh/id_ed25519
|
||||
printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /root/.ssh/config
|
||||
git clone --filter=blob:none \
|
||||
"ssh://git@gitea-sshd.foxhunt.svc.cluster.local:22/gitadmin/fxhnt.git" /workspace/src
|
||||
cd /workspace/src && git checkout "{{workflow.parameters.commit-sha}}"
|
||||
cd /workspace/src && git checkout "$COMMIT_SHA"
|
||||
|
||||
if [ "{{workflow.parameters.mode}}" != "auto" ]; then
|
||||
echo -n "{{workflow.parameters.mode}}" > /tmp/mode
|
||||
if [ "$MODE" != "auto" ]; then
|
||||
printf '%s' "$MODE" > /tmp/mode
|
||||
else
|
||||
SHA="{{workflow.parameters.commit-sha}}"
|
||||
RESOLVED="$(git rev-parse "$SHA")"
|
||||
RESOLVED="$(git rev-parse "$COMMIT_SHA")"
|
||||
if CHANGED=$(git diff --name-only "${RESOLVED}~1" "${RESOLVED}" 2>/dev/null); then
|
||||
# diff succeeded (parent exists): build only if a dep/Dockerfile file changed, else deploy.
|
||||
if echo "$CHANGED" | grep -qE '^pyproject\.toml$|^infra/docker/fxhnt\.Dockerfile$'; then
|
||||
echo -n build > /tmp/mode
|
||||
printf 'build' > /tmp/mode
|
||||
else
|
||||
echo -n deploy > /tmp/mode
|
||||
printf 'deploy' > /tmp/mode
|
||||
fi
|
||||
else
|
||||
# diff failed (no parent -- first commit / shallow history): default to build (safe, never wrong).
|
||||
echo -n build > /tmp/mode
|
||||
printf 'build' > /tmp/mode
|
||||
fi
|
||||
fi
|
||||
cat /tmp/mode
|
||||
@@ -97,16 +103,20 @@ spec:
|
||||
- name: git-clone
|
||||
image: alpine/git:latest
|
||||
command: [/bin/sh, -c]
|
||||
# SECURITY: commit-sha via ENV + hex-validated (see decide-mode note) — no inline shell substitution.
|
||||
env:
|
||||
- { name: COMMIT_SHA, value: "{{workflow.parameters.commit-sha}}" }
|
||||
args:
|
||||
- |
|
||||
set -ex
|
||||
case "$COMMIT_SHA" in *[!0-9a-fA-F]*|"") echo "refusing non-hex commit-sha" >&2; exit 1 ;; esac
|
||||
mkdir -p /root/.ssh
|
||||
cp /etc/git-ssh/ssh-privatekey /root/.ssh/id_ed25519
|
||||
chmod 600 /root/.ssh/id_ed25519
|
||||
printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /root/.ssh/config
|
||||
git clone --no-checkout --filter=blob:none \
|
||||
"ssh://git@gitea-sshd.foxhunt.svc.cluster.local:22/gitadmin/fxhnt.git" /workspace/src
|
||||
cd /workspace/src && git checkout "{{workflow.parameters.commit-sha}}"
|
||||
cd /workspace/src && git checkout "$COMMIT_SHA"
|
||||
echo "checked out $(git rev-parse --short HEAD)"
|
||||
volumeMounts:
|
||||
- { name: git-ssh-key, mountPath: /etc/git-ssh, readOnly: true }
|
||||
@@ -148,16 +158,20 @@ spec:
|
||||
- name: git-clone
|
||||
image: alpine/git:latest
|
||||
command: [/bin/sh, -c]
|
||||
# SECURITY: commit-sha via ENV + hex-validated — no inline shell substitution.
|
||||
env:
|
||||
- { name: COMMIT_SHA, value: "{{workflow.parameters.commit-sha}}" }
|
||||
args:
|
||||
- |
|
||||
set -ex
|
||||
case "$COMMIT_SHA" in *[!0-9a-fA-F]*|"") echo "refusing non-hex commit-sha" >&2; exit 1 ;; esac
|
||||
mkdir -p /root/.ssh
|
||||
cp /etc/git-ssh/ssh-privatekey /root/.ssh/id_ed25519
|
||||
chmod 600 /root/.ssh/id_ed25519
|
||||
printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /root/.ssh/config
|
||||
git clone --no-checkout --filter=blob:none \
|
||||
"ssh://git@gitea-sshd.foxhunt.svc.cluster.local:22/gitadmin/fxhnt.git" /workspace/src
|
||||
cd /workspace/src && git checkout "{{workflow.parameters.commit-sha}}"
|
||||
cd /workspace/src && git checkout "$COMMIT_SHA"
|
||||
volumeMounts:
|
||||
- { name: git-ssh-key, mountPath: /etc/git-ssh, readOnly: true }
|
||||
- { name: workspace, mountPath: /workspace }
|
||||
|
||||
Reference in New Issue
Block a user