From a2ab5ed2a33f70bdc180865bf78b09dd39fd54ce Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 4 Jun 2026 22:18:03 +0900 Subject: [PATCH] feat(security): extend secret detection coverage (GitLab/Doppler/Google) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scanner と inline-secret フックの両層に、これまで未対応だったトークン種別を 追加。検出は多層(混入を入口で止め、混入済みを scan で検出)で揃える。 ## scanner (security-credential-scan.sh) - PATTERNS に GitLab PAT (glpat-…) と Doppler Token (dp..…) を追加 - 両者を CRITICAL 重大度に分類 ## hook (block_inline_secrets.py) - SECRET_PATTERNS に Google API key (AIza…) / GitLab PAT / Doppler Token を追加 (scanner には既にあった Google を inline 側にも揃える) ## tests - security-scripts.bats: .claude 設定内の GitLab/Doppler を検出するケース追加 - hooks-command-safety.test.js: 3 種別のパターン存在アサーション追加 - behavioral 確認: 実トークン3種を block、変数参照/`doppler run`/通常commit は allow Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/hooks/block_inline_secrets.py | 3 +++ script/security-credential-scan.sh | 4 ++++ test/hooks-command-safety.test.js | 12 ++++++++++++ test/integration/security-scripts.bats | 24 ++++++++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/.claude/hooks/block_inline_secrets.py b/.claude/hooks/block_inline_secrets.py index d60c5030..bcac596a 100755 --- a/.claude/hooks/block_inline_secrets.py +++ b/.claude/hooks/block_inline_secrets.py @@ -42,6 +42,9 @@ (r"xox[baprs]-[A-Za-z0-9-]{10,}", "Slack token"), (r"[sr]k_(live|test)_[A-Za-z0-9]{24,}", "Stripe key"), (r"lin_api_[A-Za-z0-9]{43}", "Linear API key"), + (r"AIza[0-9A-Za-z_-]{35}", "Google API key"), + (r"glpat-[A-Za-z0-9_-]{20}", "GitLab personal access token"), + (r"dp\.(pt|st|sa|ct|scim|audit)\.[A-Za-z0-9]{40,}", "Doppler token"), (r"-----BEGIN[A-Z ]*PRIVATE KEY-----", "private key"), ] diff --git a/script/security-credential-scan.sh b/script/security-credential-scan.sh index 281211b1..563a9f20 100755 --- a/script/security-credential-scan.sh +++ b/script/security-credential-scan.sh @@ -106,6 +106,8 @@ PATTERNS["Supabase Key"]="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\\.[a-zA-Z0-9_-]+\ # Note: Vercel Token pattern removed (too broad, causes false positives) PATTERNS["Linear API Key"]="lin_api_[a-zA-Z0-9]{43}" PATTERNS["Sentry DSN"]="https://[a-f0-9]{32}@[a-z0-9]+\\.ingest\\.sentry\\.io/[0-9]+" +PATTERNS["GitLab PAT"]="glpat-[a-zA-Z0-9_-]{20}" +PATTERNS["Doppler Token"]="dp\\.(pt|st|sa|ct|scim|audit)\\.[a-zA-Z0-9]{40,}" # Generic Patterns PATTERNS["Private Key"]="-----BEGIN.*PRIVATE KEY-----" @@ -222,6 +224,8 @@ record_finding() { [[ "$pattern_name" == *"Stripe"* ]] || \ [[ "$pattern_name" == *"Supabase"* ]] || \ [[ "$pattern_name" == *"Slack Token"* ]] || \ + [[ "$pattern_name" == *"GitLab"* ]] || \ + [[ "$pattern_name" == *"Doppler"* ]] || \ [[ "$pattern_name" == *"Database URL"* ]]; then severity="CRITICAL" CRITICAL_COUNT=$((CRITICAL_COUNT + 1)) diff --git a/test/hooks-command-safety.test.js b/test/hooks-command-safety.test.js index 4852157f..e720f00f 100644 --- a/test/hooks-command-safety.test.js +++ b/test/hooks-command-safety.test.js @@ -142,6 +142,18 @@ describe('Claude Code command-safety hooks', () => { expect(content).toContain('sk-ant-'); }); + test('should detect Google API keys', () => { + expect(content).toContain('AIza'); + }); + + test('should detect GitLab personal access tokens', () => { + expect(content).toContain('glpat-'); + }); + + test('should detect Doppler tokens', () => { + expect(content).toContain('Doppler token'); + }); + test('should detect private key blocks', () => { expect(content).toContain('PRIVATE KEY'); }); diff --git a/test/integration/security-scripts.bats b/test/integration/security-scripts.bats index f02e4cc5..a2d09d05 100644 --- a/test/integration/security-scripts.bats +++ b/test/integration/security-scripts.bats @@ -199,6 +199,30 @@ JS assert_output --partial "Azure Service Principal" } +@test "security-credential-scan.sh detects GitLab and Doppler tokens" { + mkdir -p "$TEST_TEMP_DIR/.claude" + # Build tokens at runtime so no literal secret pattern lives in the source + # (GitHub push protection blocks pushes that contain valid token shapes). + gl="glpat-$(printf 'x%.0s' $(seq 20))" + dp="dp.pt.$(printf 'x%.0s' $(seq 40))" + cat > "$TEST_TEMP_DIR/.claude/settings.local.json" <= 2' >/dev/null + assert_output --partial "GitLab PAT" + assert_output --partial "Doppler Token" +} + @test "security-credential-scan.sh ignores Nix flake.lock rev hashes" { mkdir -p "$TEST_TEMP_DIR/nix" cat > "$TEST_TEMP_DIR/nix/flake.lock" <<'JSON'