1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
package detector
import "regexp"
type secretRule struct {
id string
pattern *regexp.Regexp
secretGroup int
confidence float64
}
var secretRules []secretRule
func init() {
type raw struct {
id string
pat string
group int
sev string
}
sev := map[string]float64{
"CRITICAL": 1.0, "HIGH": 0.9, "MEDIUM": 0.75, "LOW": 0.6, "WARNING": 0.5,
}
rules := []raw{
// Cloud / VCS
{"aws-access-key", `(?i)(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}`, 0, "CRITICAL"},
{"aws-secret-key", `(?i)aws[_\-\s\.]{0,5}secret[_\-\s\.]{0,5}(access[_\-\s\.]{0,5})?key["'\s]*[:=]["'\s]*([A-Za-z0-9+/]{40})`, 2, "CRITICAL"},
{"github-pat", `(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,255}`, 0, "CRITICAL"},
{"github-fine-grained-pat", `github_pat_[A-Za-z0-9_]{82}`, 0, "CRITICAL"},
{"gitlab-pat", `glpat-[A-Za-z0-9\-]{20}`, 0, "CRITICAL"},
{"google-api-key", `AIza[0-9A-Za-z\-_]{35}`, 0, "HIGH"},
{"google-oauth-client", `GOCSPX-[A-Za-z0-9\-_]{28}`, 0, "HIGH"},
{"stripe-secret", `sk_(live|test)_[A-Za-z0-9]{24,}`, 0, "CRITICAL"},
{"stripe-publishable", `pk_(live|test)_[A-Za-z0-9]{24,}`, 0, "LOW"},
{"slack-token", `xox[baprs]-([0-9a-zA-Z]{10,48})`, 0, "HIGH"},
{"slack-webhook", `https://hooks\.slack\.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]+`, 0, "HIGH"},
{"sendgrid-api", `SG\.[A-Za-z0-9\-_]{22}\.[A-Za-z0-9\-_]{43}`, 0, "HIGH"},
{"twilio-account-sid", `AC[a-z0-9]{32}`, 0, "HIGH"},
{"jwt-token", `eyJ[A-Za-z0-9\-_=]+\.[A-Za-z0-9\-_=]+\.?[A-Za-z0-9\-_.+/=]*`, 0, "MEDIUM"},
{"private-key-header", `-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY( BLOCK)?-----`, 0, "CRITICAL"},
{"generic-secret", `(?i)(secret|password|passwd|pwd|api[_-]?key|auth[_-]?token|access[_-]?token)["'\s]*[:=]["'\s]+([A-Za-z0-9!@#$%^&*()\-_+=]{16,})`, 2, "MEDIUM"},
{"npm-token", `npm_[A-Za-z0-9]{36}`, 0, "HIGH"},
{"docker-hub-pat", `dckr_pat_[A-Za-z0-9\-_]{27}`, 0, "HIGH"},
// LLM / AI
{"openai-api-key", `sk-(?:proj-|svcacct-)?[A-Za-z0-9\-_]{32,}T3BlbkFJ[A-Za-z0-9\-_]{20,}`, 0, "CRITICAL"},
{"openai-api-key-new", `sk-proj-[A-Za-z0-9\-_]{50,}`, 0, "CRITICAL"},
{"anthropic-api-key", `sk-ant-(?:api03-)?[A-Za-z0-9\-_]{32,}`, 0, "CRITICAL"},
{"cohere-api-key", `(?i)(?:cohere[._-]?(?:api[._-]?)?key|CO_API_KEY)\s*[=:]\s*([A-Za-z0-9]{40})`, 1, "CRITICAL"},
{"mistral-api-key", `(?i)(?:mistral[._-]?(?:api[._-]?)?key|MISTRAL_API_KEY)\s*[=:]\s*([A-Za-z0-9]{32})`, 1, "CRITICAL"},
{"huggingface-token", `hf_[A-Za-z0-9]{32,}`, 0, "HIGH"},
{"huggingface-token-env", `(?i)(?:HUGGING_FACE|HUGGINGFACE)[._-]?(?:HUB[._-]?)?TOKEN\s*[=:]\s*([A-Za-z0-9_\-]{20,})`, 1, "HIGH"},
{"replicate-api-key", `r8_[A-Za-z0-9]{32,}`, 0, "HIGH"},
{"together-ai-key", `(?i)TOGETHER[._-]?API[._-]?KEY\s*[=:]\s*([A-Za-z0-9]{64})`, 1, "CRITICAL"},
{"perplexity-api-key", `pplx-[A-Za-z0-9]{48}`, 0, "HIGH"},
{"groq-api-key", `gsk_[A-Za-z0-9]{52}`, 0, "HIGH"},
{"xai-api-key", `xai-[A-Za-z0-9]{32,}`, 0, "CRITICAL"},
{"azure-openai-key", `(?i)(?:AZURE[._-]?OPENAI[._-]?(?:API[._-]?)?KEY)\s*[=:]\s*([a-f0-9]{32})`, 1, "CRITICAL"},
{"stability-ai-key", `sk-[A-Za-z0-9]{48}\b`, 0, "HIGH"},
// Azure / Entra / M365
{"azure-tenant-id", `(?i)(?:tenant[_-]?id|AZURE_TENANT_ID|tenantId)\s*[=:]\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})`, 1, "MEDIUM"},
{"azure-client-id", `(?i)(?:client[_-]?id|app[_-]?id|AZURE_CLIENT_ID|clientId|applicationId)\s*[=:]\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})`, 1, "MEDIUM"},
{"azure-client-secret", `(?i)(?:client[_-]?secret|AZURE_CLIENT_SECRET|clientSecret)\s*[=:]\s*([A-Za-z0-9~._\-]{34,})`, 1, "CRITICAL"},
{"azure-subscription-key", `(?i)(?:Ocp-Apim-Subscription-Key|subscription[_-]?key|APIM[_-]?KEY)\s*[=:]\s*([a-f0-9]{32})`, 1, "CRITICAL"},
{"azure-storage-account-key", `(?i)(?:AccountKey|AZURE_STORAGE_KEY|storageAccountKey)\s*[=:]\s*([A-Za-z0-9+/]{86}==)`, 1, "CRITICAL"},
{"azure-storage-connection-string", `DefaultEndpointsProtocol=https?;AccountName=[^;]+;AccountKey=[A-Za-z0-9+/]{86}==[^;]*`, 0, "CRITICAL"},
{"azure-sas-token", `(?:sv|sig|se|sp)=[A-Za-z0-9%+/=&\-]{8,}(?:&(?:sv|sig|se|sp|spr|srt|ss)=[A-Za-z0-9%+/=&\-]{4,}){3,}`, 0, "CRITICAL"},
{"azure-function-key", `(?i)(?:x-functions-key|AZURE_FUNCTION_KEY|functionKey)\s*[=:]\s*([A-Za-z0-9/+]{40,}={0,2})`, 1, "HIGH"},
{"azure-service-bus-connstr", `Endpoint=sb://[^;]+\.servicebus\.windows\.net/;SharedAccessKeyName=[^;]+;SharedAccessKey=[A-Za-z0-9+/]{43}=`, 0, "CRITICAL"},
{"azure-eventhub-connstr", `Endpoint=sb://[^;]+\.servicebus\.windows\.net/;SharedAccessKeyName=[^;]+;SharedAccessKey=[A-Za-z0-9+/]{43}=;EntityPath=[^\s]+`, 0, "CRITICAL"},
{"azure-cosmosdb-key", `(?i)(?:cosmos[._-]?(?:db[._-]?)?(?:account[._-]?)?key|COSMOS_KEY)\s*[=:]\s*([A-Za-z0-9+/]{86}==)`, 1, "CRITICAL"},
{"azure-search-admin-key", `(?i)(?:search[._-]?(?:admin[._-]?)?key|AZURE_SEARCH_KEY)\s*[=:]\s*([A-Za-z0-9]{32})`, 1, "CRITICAL"},
{"azure-cognitive-key", `(?i)(?:cognitive[._-]?(?:services[._-]?)?key|AZURE_COGNITIVE_KEY)\s*[=:]\s*([a-f0-9]{32})`, 1, "CRITICAL"},
{"azure-iot-hub-connstr", `HostName=[^;]+\.azure-devices\.net;SharedAccessKeyName=[^;]+;SharedAccessKey=[A-Za-z0-9+/]{43}=`, 0, "CRITICAL"},
{"sharepoint-client-secret", `(?i)(?:SharePoint|SPO|M365)[._-]?(?:client[._-]?)?secret\s*[=:]\s*([A-Za-z0-9+/]{32,}={0,2})`, 1, "CRITICAL"},
{"graph-api-client-secret", `(?i)(?:graph[._-]?(?:api[._-]?)?(?:client[._-]?)?secret|MS_GRAPH_SECRET)\s*[=:]\s*([A-Za-z0-9~._\-]{34,})`, 1, "CRITICAL"},
{"teams-webhook", `https://[a-zA-Z0-9\-]+\.webhook\.office\.com/webhookb2/[A-Za-z0-9\-@]+/IncomingWebhook/[A-Za-z0-9]+/[A-Za-z0-9\-]+`, 0, "HIGH"},
{"power-automate-shared-key", `(?i)(?:LogicApp|PowerAutomate|flow)[._-]?(?:shared[._-]?)?(?:access[._-]?)?key\s*[=:]\s*([A-Za-z0-9+/]{40,}={0,2})`, 1, "HIGH"},
// Frontend / SaaS
{"firebase-private-key", `(?i)(?:firebase|FIREBASE)[._-]?(?:admin[._-]?)?(?:private[._-]?)?key[._-]?(?:id)?\s*[=:]\s*([A-Za-z0-9]{40})`, 1, "CRITICAL"},
{"mapbox-public-token", `pk\.eyJ[A-Za-z0-9\-_=]+\.[A-Za-z0-9\-_=]+`, 0, "LOW"},
{"mapbox-secret-token", `sk\.eyJ[A-Za-z0-9\-_=]+\.[A-Za-z0-9\-_=]+`, 0, "HIGH"},
{"sentry-dsn", `https://[a-f0-9]{32}@[a-z0-9\-]+\.ingest\.sentry\.io/[0-9]+`, 0, "MEDIUM"},
{"contentful-pat", `CFPAT-[A-Za-z0-9\-_]{43}`, 0, "HIGH"},
{"shopify-pat", `shpat_[A-Fa-f0-9]{32}`, 0, "CRITICAL"},
{"shopify-shared-secret", `shpss_[A-Fa-f0-9]{32}`, 0, "CRITICAL"},
{"shopify-custom-app", `shpca_[A-Fa-f0-9]{32}`, 0, "CRITICAL"},
{"shopify-private-app", `shppa_[A-Fa-f0-9]{32}`, 0, "CRITICAL"},
{"algolia-admin-key", `(?i)(?:algolia[._-]?(?:admin[._-]?)?(?:api[._-]?)?key|ALGOLIA_ADMIN_KEY)\s*[=:]["'\s]*([a-f0-9]{32})`, 1, "CRITICAL"},
{"linear-api-key", `lin_api_[A-Za-z0-9]{40}`, 0, "HIGH"},
{"postman-api-key", `PMAK-[A-Za-z0-9\-]{58,}`, 0, "HIGH"},
{"planetscale-token", `pscale_tkn_[A-Za-z0-9\-_]{43}`, 0, "HIGH"},
{"cloudflare-api-token", `(?i)(?:CF[._-]?API[._-]?TOKEN|CLOUDFLARE[._-]?(?:API[._-]?)?TOKEN)\s*[=:]\s*([A-Za-z0-9\-_]{40})`, 1, "HIGH"},
{"cloudflare-api-key", `(?i)(?:CF[._-]?API[._-]?KEY|CLOUDFLARE[._-]?(?:API[._-]?)?KEY)\s*[=:]\s*([a-f0-9]{37})`, 1, "CRITICAL"},
// Database
{"db-postgres-url", `postgres(?:ql)?://[^:@\s]+:[^:@\s]+@[^/\s]+/\S+`, 0, "CRITICAL"},
{"db-mysql-url", `mysql(?:2)?://[^:@\s]+:[^:@\s]+@[^/\s]+/\S+`, 0, "CRITICAL"},
{"db-mongodb-url", `mongodb(?:\+srv)?://[^:@\s]+:[^:@\s]+@[^/\s]+(?:/\S*)?`, 0, "CRITICAL"},
{"db-redis-url", `rediss?://(?:[^:@\s]+:)[^@\s]+@[^/\s]+(?:/\d+)?`, 0, "HIGH"},
{"db-mssql-connstr", `(?i)(?:Server|Data Source)=[^;]+;[^;]*(?:Password|PWD)=([^;]+)`, 1, "CRITICAL"},
{"db-elasticsearch-url", `https?://[^:@\s]+:[^:@\s]+@[^/\s]*(?:920[0-9]|930[0-9])[^\s]*`, 0, "HIGH"},
{"db-amqp-url", `amqps?://[^:@\s]+:[^:@\s]+@[^/\s]+`, 0, "HIGH"},
{"db-generic-password", `(?i)(?:db|database)[_\-\.]?(?:password|passwd|pwd)\s*[=:]\s*[^\s"']{8,}`, 0, "HIGH"},
{"db-jdbc-url", `jdbc:[a-z0-9]+://[^:@\s]*:[^@\s]+@[^\s]+`, 0, "CRITICAL"},
// Observability
{"otel-endpoint-with-auth", `https?://[^:@\s]+:[^:@\s]+@[^\s]*(?:4317|4318|otlp|otel|opentelemetry)[^\s]*`, 0, "HIGH"},
{"otel-exporter-headers", `(?i)OTEL_EXPORTER_OTLP_HEADERS\s*=\s*[^\n]*(?:api[_-]?key|authorization|x-honeycomb-team)=[A-Za-z0-9\-_+/=]{12,}`, 0, "HIGH"},
{"honeycomb-api-key", `(?i)(?:x-honeycomb-team|honeycomb[._-]?(?:api[._-]?)?key)\s*[=:]\s*([A-Za-z0-9]{22,})`, 1, "HIGH"},
{"datadog-api-key", `(?i)(?:DD_API_KEY|datadog[._-]?api[._-]?key)\s*[=:]\s*([a-f0-9]{32})`, 1, "HIGH"},
{"newrelic-license-key", `(?i)(?:NEW_RELIC_LICENSE_KEY|newrelic[._-]?license[._-]?key)\s*[=:]\s*([A-Za-z0-9]{40})`, 1, "HIGH"},
{"grafana-service-account", `glsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8}`, 0, "HIGH"},
{"lightstep-token", `(?i)(?:x-lightstep-access-token|lightstep[._-]?token)\s*[=:]\s*([A-Za-z0-9\-_]{20,})`, 1, "HIGH"},
// HTTP Auth
{"http-bearer-header", `(?i)(?:Authorization|auth)\s*[:=]\s*Bearer\s+([A-Za-z0-9\-_=+/.]{16,})`, 1, "HIGH"},
{"http-bearer-env", `(?i)BEARER[_-]?TOKEN\s*[=:]\s*([A-Za-z0-9\-_=+/.]{16,})`, 1, "HIGH"},
{"http-bearer-curl", `(?i)curl\s+[^\n]*-H\s+"Authorization:\s*Bearer\s+([A-Za-z0-9\-_=+/.]{16,})"`, 1, "HIGH"},
// Infrastructure / CI
{"vault-service-token", `hvs\.[A-Za-z0-9_-]{24,}`, 0, "CRITICAL"},
{"vault-batch-token", `hvb\.[A-Za-z0-9_-]{24,}`, 0, "CRITICAL"},
{"terraform-cloud-token", `TFC-[A-Za-z0-9]{14,}`, 0, "CRITICAL"},
{"digitalocean-pat", `dop_v1_[a-f0-9]{64}`, 0, "CRITICAL"},
{"circleci-token", `ccipat_[A-Za-z0-9]{40,}`, 0, "HIGH"},
// Email providers
{"mailgun-api-key", `\bkey-[a-f0-9]{32}\b`, 0, "HIGH"},
{"postmark-server-token", `(?i)(?:POSTMARK[._-]?(?:SERVER[._-]?)?(?:API[._-]?)?TOKEN|X-Postmark-Server-Token)\s*[=:]\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})`, 1, "HIGH"},
// Database / BaaS
{"supabase-pat", `sbp_[a-f0-9]{40}`, 0, "CRITICAL"},
{"supabase-service-role", `(?i)SUPABASE[._-]?(?:SERVICE[._-]?ROLE[._-]?)?KEY\s*[=:]\s*(eyJ[A-Za-z0-9_-]{30,}\.[A-Za-z0-9_-]{30,}\.[A-Za-z0-9_-]{27,})`, 1, "CRITICAL"},
// AI / Embeddings
{"pinecone-api-key", `pcsk_[A-Za-z0-9_]{40,}`, 0, "CRITICAL"},
{"elevenlabs-api-key", `(?i)(?:ELEVENLABS[._-]?(?:API[._-]?)?KEY|XI_API_KEY)\s*[=:]\s*([a-f0-9]{32})`, 1, "HIGH"},
{"openai-api-key-env", `(?i)(?:OPENAI[._-]?API[._-]?KEY)\s*[=:]\s*(sk-(?:proj-|svcacct-)?[A-Za-z0-9\-_]{20,})`, 1, "CRITICAL"},
{"anthropic-api-key-env", `(?i)(?:ANTHROPIC[._-]?API[._-]?KEY)\s*[=:]\s*(sk-ant-(?:api03-)?[A-Za-z0-9\-_]{16,})`, 1, "CRITICAL"},
// Python / LLM
{"python-llm-key-assignment", `(?i)\b(?:openai|anthropic|azure_openai|mistral|cohere|groq|together|huggingface|hf|replicate|perplexity|xai|langsmith|pinecone|weaviate)[._-]?(?:api[._-]?)?(?:key|token|secret)\b\s*=\s*["'][^"'\n]{16,}["']`, 0, "CRITICAL"},
{"python-dotenv-llm-key", `(?im)^\s*(?:OPENAI|ANTHROPIC|AZURE_OPENAI|MISTRAL|COHERE|GROQ|TOGETHER|HUGGINGFACE|HF|REPLICATE|PERPLEXITY|XAI|LANGSMITH|PINECONE|WEAVIATE)[A-Z0-9_]*_(?:API_)?(?:KEY|TOKEN|SECRET)\s*=\s*[^\s#]{16,}\s*$`, 0, "CRITICAL"},
{"langsmith-api-key-env", `(?i)\b(?:LANGSMITH|LANGCHAIN)[A-Z0-9_]*_(?:API_)?KEY\s*[=:]\s*([A-Za-z0-9_\-]{20,})`, 1, "CRITICAL"},
{"python-os-environ-secret", `(?i)\bos\.environ\[\s*["'][A-Z0-9_]*(?:API_)?(?:KEY|TOKEN|SECRET)[A-Z0-9_]*["']\s*\]\s*=\s*["'][^"'\n]{12,}["']`, 0, "HIGH"},
{"python-openai-client-inline-key", `(?i)\bOpenAI\s*\(\s*api_key\s*=\s*["'][^"'\n]{16,}["']`, 0, "CRITICAL"},
{"python-anthropic-client-inline-key", `(?i)\bAnthropic\s*\(\s*api_key\s*=\s*["'][^"'\n]{16,}["']`, 0, "CRITICAL"},
{"vertex-private-key-json", `"private_key"\s*:\s*"-----BEGIN PRIVATE KEY-----`, 0, "CRITICAL"},
{"aws-bedrock-access-key-env", `(?i)\bAWS_ACCESS_KEY_ID\s*[=:]\s*((?:AKIA|ASIA)[A-Z0-9]{16})`, 1, "CRITICAL"},
{"aws-bedrock-secret-key-env", `(?i)\bAWS_SECRET_ACCESS_KEY\s*[=:]\s*([A-Za-z0-9/+=]{40})`, 1, "CRITICAL"},
{"streamlit-secrets-llm-key", `(?i)\b(?:openai|anthropic|langsmith|cohere|mistral|groq|together|huggingface|replicate|perplexity|xai)[._-]?(?:api[._-]?)?(?:key|token|secret)\s*=\s*["'][^"'\n]{16,}["']`, 0, "CRITICAL"},
// Communication
{"slack-signing-secret", `(?i)(?:SLACK_SIGNING_SECRET|slack[._-]?signing[._-]?secret)\s*[=:]\s*([a-f0-9]{32})`, 1, "HIGH"},
{"slack-app-token", `xapp-[0-9]-[A-Z0-9]+-[0-9]+-[a-f0-9]{64}`, 0, "HIGH"},
{"twilio-auth-token", `(?i)TWILIO[._-]?AUTH[._-]?TOKEN\s*[=:]\s*([a-f0-9]{32})`, 1, "CRITICAL"},
{"discord-bot-token", `(?i)(?:discord[._-]?(?:bot[._-]?)?token|DISCORD_TOKEN)\s*[=:]\s*([A-Za-z0-9_-]{24,26}\.[A-Za-z0-9_-]{6}\.[A-Za-z0-9_-]{27,})`, 1, "HIGH"},
{"telegram-bot-token", `[0-9]{8,12}:[A-Za-z0-9_-]{35}`, 0, "HIGH"},
{"notion-integration-token", `secret_[A-Za-z0-9]{43}`, 0, "HIGH"},
{"notion-oauth-token", `ntn_[A-Za-z0-9]{40,}`, 0, "HIGH"},
// GCP
{"gcp-service-account", `"type"\s*:\s*"service_account"`, 0, "CRITICAL"},
}
for _, r := range rules {
re, err := regexp.Compile(r.pat)
if err != nil {
continue
}
secretRules = append(secretRules, secretRule{
id: r.id, pattern: re, secretGroup: r.group,
confidence: sev[r.sev],
})
}
}
func detectSecrets(text string) []Finding {
var out []Finding
for _, rule := range secretRules {
for _, m := range rule.pattern.FindAllStringSubmatchIndex(text, -1) {
si, ei := rule.secretGroup*2, rule.secretGroup*2+1
if ei >= len(m) || m[si] < 0 {
continue
}
out = append(out, Finding{
Type: PiiSecret, Start: m[si], End: m[ei],
Text: text[m[si]:m[ei]], Confidence: rule.confidence, RuleID: rule.id,
})
}
}
return out
}
|