From dc7322f4b2dc3ec3bb1fc3580b732c5c7029a65d Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 21 May 2026 07:30:11 +0100 Subject: [PATCH] security(avow-protocol): remove leaked Cloudflare API token + harden scanner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A real Cloudflare API token was hardcoded at avow-protocol/deploy-repos.sh:5 in commit 5f2f8b2 (2026-05-18) and reported externally on 2026-05-21. Changes: - deploy-repos.sh: source CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID from env with hard-fail if unset (matches the pattern already used in avow-protocol/deploy-cloudflare.sh:60-72). - DEPLOYMENT-SUCCESS.md: redact the account ID from the public doc. - secret-scanner.yml: add a shell-secrets job (mirrors rust-secrets). The existing trufflehog --only-verified + gitleaks defaults both missed this leak at PR time; the new grep-based job would have caught it (self-tested). Owner actions (out of band, not in this PR): 1. Rotate / delete the leaked token at Cloudflare → API Tokens (token id 689fa59a165c47cc61095d984c453205) — repo is public so the secret should be considered burned regardless of history rewrite. 2. History rewrite + force-push affected branches (tracked separately). Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/secret-scanner.yml | 35 ++++++++++++++++++++++++++++ avow-protocol/DEPLOYMENT-SUCCESS.md | 2 +- avow-protocol/deploy-repos.sh | 14 +++++++++-- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/.github/workflows/secret-scanner.yml b/.github/workflows/secret-scanner.yml index cb9cdf88..a2af7ade 100644 --- a/.github/workflows/secret-scanner.yml +++ b/.github/workflows/secret-scanner.yml @@ -79,3 +79,38 @@ jobs: echo "::error::Potential hardcoded secrets detected. Use environment variables instead." exit 1 fi + + # Shell-specific: catch hardcoded credentials in shell scripts. + # Added 2026-05-21 after trufflehog --only-verified + gitleaks defaults + # both missed a real Cloudflare API token leaked via avow-protocol/deploy-repos.sh. + shell-secrets: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 + + - name: Check for hardcoded secrets in shell scripts + run: | + # Patterns: an `export FOO=` or `FOO=` with a quoted literal of meaningful length. + # Restricted to *_TOKEN / *_KEY / *_SECRET / PASSWORD to keep false-positives low. + PATTERNS=( + '(export[[:space:]]+)?[A-Z_]*TOKEN[A-Z_]*=["'"'"'][A-Za-z0-9_./+=-]{20,}["'"'"']' + '(export[[:space:]]+)?[A-Z_]*API_KEY[A-Z_]*=["'"'"'][A-Za-z0-9_./+=-]{20,}["'"'"']' + '(export[[:space:]]+)?[A-Z_]*SECRET[A-Z_]*=["'"'"'][A-Za-z0-9_./+=-]{16,}["'"'"']' + '(export[[:space:]]+)?PASSWORD=["'"'"'][^"'"'"']{6,}["'"'"']' + ) + + found=0 + for pattern in "${PATTERNS[@]}"; do + # --include covers *.sh and *.bash; add new shell extensions here if needed. + if grep -rnE --include='*.sh' --include='*.bash' \ + --exclude-dir='.git' --exclude-dir='node_modules' --exclude-dir='target' \ + "$pattern" . ; then + echo "::warning::Potential hardcoded secret matching: $pattern" + found=1 + fi + done + + if [ $found -eq 1 ]; then + echo "::error::Hardcoded secret detected in a shell script. Source from env (see avow-protocol/deploy-repos.sh) instead." + exit 1 + fi diff --git a/avow-protocol/DEPLOYMENT-SUCCESS.md b/avow-protocol/DEPLOYMENT-SUCCESS.md index 3b28a915..98de23cd 100644 --- a/avow-protocol/DEPLOYMENT-SUCCESS.md +++ b/avow-protocol/DEPLOYMENT-SUCCESS.md @@ -39,7 +39,7 @@ **API Authentication:** - Cloudflare API Token (with Pages Edit permissions) -- Account ID: b72dd54ed3ee66088950c82e0301edbb +- Account ID: (private — see ~/.config/hyperpolymath/cloudflare.env) **Deployment Method:** ```bash diff --git a/avow-protocol/deploy-repos.sh b/avow-protocol/deploy-repos.sh index f95290f3..daf3b64a 100755 --- a/avow-protocol/deploy-repos.sh +++ b/avow-protocol/deploy-repos.sh @@ -1,9 +1,19 @@ #!/usr/bin/env bash # SPDX-License-Identifier: PMPL-1.0-or-later # Deploy all repos to Cloudflare Pages +# +# Required environment: +# CLOUDFLARE_API_TOKEN Cloudflare API token with Pages:Edit +# CLOUDFLARE_ACCOUNT_ID Cloudflare account ID +# +# Source these from a private location (e.g. ~/.config/hyperpolymath/cloudflare.env) +# before invoking. Do NOT hardcode them in this file. -export CLOUDFLARE_API_TOKEN="xjmFyko52yeQ-3DPYxDTOZwM3DYwqRFU84f0UN40" -export CLOUDFLARE_ACCOUNT_ID="b72dd54ed3ee66088950c82e0301edbb" +set -euo pipefail + +: "${CLOUDFLARE_API_TOKEN:?CLOUDFLARE_API_TOKEN must be set (do not hardcode)}" +: "${CLOUDFLARE_ACCOUNT_ID:?CLOUDFLARE_ACCOUNT_ID must be set (do not hardcode)}" +export CLOUDFLARE_API_TOKEN CLOUDFLARE_ACCOUNT_ID REPOS_DIR="$HOME/Documents/hyperpolymath-repos"