// Copyright 2026 MarketAlly. All rights reserved. // SPDX-License-Identifier: MIT package secretscan import "regexp" // Severity represents the severity level of a detected secret type Severity string const ( SeverityCritical Severity = "critical" SeverityHigh Severity = "high" SeverityMedium Severity = "medium" SeverityLow Severity = "low" ) // Category represents the category of a detected secret type Category string const ( CategoryAPIKey Category = "api-key" CategoryPrivateKey Category = "private-key" CategoryPassword Category = "password" CategoryToken Category = "token" CategoryCertificate Category = "certificate" CategoryConnectionString Category = "connection-string" CategoryCredential Category = "credential" CategorySecret Category = "secret" ) // Pattern represents a secret detection pattern type Pattern struct { ID string Name string Description string Regex *regexp.Regexp Severity Severity Category Category FalsePositiveRegexes []*regexp.Regexp } // builtinPatterns contains all built-in secret detection patterns var builtinPatterns = []Pattern{ // ============================================ // PRIVATE KEYS (Critical) // ============================================ { ID: "private-key-rsa", Name: "RSA Private Key", Description: "RSA private key in PEM format", Regex: regexp.MustCompile(`-----BEGIN (?:RSA )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA )?PRIVATE KEY-----`), Severity: SeverityCritical, Category: CategoryPrivateKey, }, { ID: "private-key-openssh", Name: "OpenSSH Private Key", Description: "OpenSSH private key", Regex: regexp.MustCompile(`-----BEGIN OPENSSH PRIVATE KEY-----[\s\S]*?-----END OPENSSH PRIVATE KEY-----`), Severity: SeverityCritical, Category: CategoryPrivateKey, }, { ID: "private-key-ec", Name: "EC Private Key", Description: "Elliptic Curve private key", Regex: regexp.MustCompile(`-----BEGIN EC PRIVATE KEY-----[\s\S]*?-----END EC PRIVATE KEY-----`), Severity: SeverityCritical, Category: CategoryPrivateKey, }, { ID: "private-key-dsa", Name: "DSA Private Key", Description: "DSA private key", Regex: regexp.MustCompile(`-----BEGIN DSA PRIVATE KEY-----[\s\S]*?-----END DSA PRIVATE KEY-----`), Severity: SeverityCritical, Category: CategoryPrivateKey, }, { ID: "private-key-pgp", Name: "PGP Private Key", Description: "PGP/GPG private key block", Regex: regexp.MustCompile(`-----BEGIN PGP PRIVATE KEY BLOCK-----[\s\S]*?-----END PGP PRIVATE KEY BLOCK-----`), Severity: SeverityCritical, Category: CategoryPrivateKey, }, // ============================================ // AWS (Critical) // ============================================ { ID: "aws-access-key", Name: "AWS Access Key ID", Description: "Amazon Web Services access key identifier", Regex: regexp.MustCompile(`\b(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}\b`), Severity: SeverityCritical, Category: CategoryAPIKey, }, { ID: "aws-mws-key", Name: "AWS MWS Key", Description: "Amazon Marketplace Web Service key", Regex: regexp.MustCompile(`(?i)amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`), Severity: SeverityCritical, Category: CategoryAPIKey, }, // ============================================ // GOOGLE / GCP (Critical) // ============================================ { ID: "gcp-api-key", Name: "Google API Key", Description: "Google Cloud Platform API key", Regex: regexp.MustCompile(`AIza[0-9A-Za-z_-]{35}`), Severity: SeverityCritical, Category: CategoryAPIKey, }, { ID: "gcp-service-account", Name: "GCP Service Account", Description: "Google Cloud service account key file", Regex: regexp.MustCompile(`"type"\s*:\s*"service_account"[\s\S]*?"private_key"`), Severity: SeverityCritical, Category: CategoryPrivateKey, }, // ============================================ // AZURE (Critical) // ============================================ { ID: "azure-connection-string", Name: "Azure Connection String", Description: "Azure service connection string", Regex: regexp.MustCompile(`(?i)DefaultEndpointsProtocol=https?;AccountName=[^;]+;AccountKey=[A-Za-z0-9/+=]+`), Severity: SeverityCritical, Category: CategoryConnectionString, }, // ============================================ // GITHUB (High) // ============================================ { ID: "github-token", Name: "GitHub Token", Description: "GitHub personal access token or OAuth token", Regex: regexp.MustCompile(`\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b`), Severity: SeverityHigh, Category: CategoryToken, }, // ============================================ // GITLAB (High) // ============================================ { ID: "gitlab-token", Name: "GitLab Token", Description: "GitLab personal access token", Regex: regexp.MustCompile(`\bglpat-[A-Za-z0-9_-]{20,}\b`), Severity: SeverityHigh, Category: CategoryToken, }, // ============================================ // STRIPE (Critical) // ============================================ { ID: "stripe-secret-key", Name: "Stripe Secret Key", Description: "Stripe API secret key", Regex: regexp.MustCompile(`\bsk_live_[0-9a-zA-Z]{24,}\b`), Severity: SeverityCritical, Category: CategoryAPIKey, }, { ID: "stripe-test-key", Name: "Stripe Test Key", Description: "Stripe API test key (still sensitive)", Regex: regexp.MustCompile(`\bsk_test_[0-9a-zA-Z]{24,}\b`), Severity: SeverityMedium, Category: CategoryAPIKey, }, // ============================================ // SLACK (High) // ============================================ { ID: "slack-token", Name: "Slack Token", Description: "Slack API token", Regex: regexp.MustCompile(`\bxox[baprs]-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*\b`), Severity: SeverityHigh, Category: CategoryToken, }, { ID: "slack-webhook", Name: "Slack Webhook URL", Description: "Slack incoming webhook URL", Regex: regexp.MustCompile(`https://hooks\.slack\.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]+`), Severity: SeverityHigh, Category: CategoryCredential, }, // ============================================ // TWILIO (High) // ============================================ { ID: "twilio-api-key", Name: "Twilio API Key", Description: "Twilio API key SID", Regex: regexp.MustCompile(`\bSK[0-9a-fA-F]{32}\b`), Severity: SeverityHigh, Category: CategoryAPIKey, }, // ============================================ // SENDGRID (High) // ============================================ { ID: "sendgrid-api-key", Name: "SendGrid API Key", Description: "SendGrid email API key", Regex: regexp.MustCompile(`\bSG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}\b`), Severity: SeverityHigh, Category: CategoryAPIKey, }, // ============================================ // NPM (High) // ============================================ { ID: "npm-token", Name: "NPM Access Token", Description: "NPM registry access token", Regex: regexp.MustCompile(`\bnpm_[A-Za-z0-9]{36}\b`), Severity: SeverityHigh, Category: CategoryToken, }, // ============================================ // DATABASE CONNECTION STRINGS (Critical) // ============================================ { ID: "postgres-uri", Name: "PostgreSQL Connection URI", Description: "PostgreSQL connection string with credentials", Regex: regexp.MustCompile(`(?i)postgres(?:ql)?://[^:]+:[^@]+@[^/]+/[^\s"']+`), Severity: SeverityCritical, Category: CategoryConnectionString, }, { ID: "mysql-uri", Name: "MySQL Connection URI", Description: "MySQL connection string with credentials", Regex: regexp.MustCompile(`(?i)mysql://[^:]+:[^@]+@[^/]+/[^\s"']+`), Severity: SeverityCritical, Category: CategoryConnectionString, }, { ID: "mongodb-uri", Name: "MongoDB Connection URI", Description: "MongoDB connection string with credentials", Regex: regexp.MustCompile(`(?i)mongodb(?:\+srv)?://[^:]+:[^@]+@[^/]+`), Severity: SeverityCritical, Category: CategoryConnectionString, }, // ============================================ // GENERIC PASSWORDS (High) // ============================================ { ID: "password-assignment", Name: "Password Assignment", Description: "Hardcoded password in code", Regex: regexp.MustCompile(`(?i)(?:password|passwd|pwd|secret|api_?key|auth_?token|access_?token)\s*[:=]\s*['"][^'"]{8,}['"]`), Severity: SeverityHigh, Category: CategoryPassword, FalsePositiveRegexes: []*regexp.Regexp{ regexp.MustCompile(`\$\{.*\}`), // Template variables regexp.MustCompile(`process\.env`), // Environment references regexp.MustCompile(`\{\{.*\}\}`), // Handlebars/mustache regexp.MustCompile(`<.*>`), // Placeholder text regexp.MustCompile(`(?i)example`), // Example text regexp.MustCompile(`(?i)placeholder`), }, }, // ============================================ // JWT (Medium) // ============================================ { ID: "jwt-token", Name: "JSON Web Token", Description: "JWT token (may contain sensitive claims)", Regex: regexp.MustCompile(`\beyJ[A-Za-z0-9_-]*\.eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*`), Severity: SeverityMedium, Category: CategoryToken, }, // ============================================ // DISCORD (High) // ============================================ { ID: "discord-token", Name: "Discord Bot Token", Description: "Discord bot or user token", Regex: regexp.MustCompile(`[MN][A-Za-z\d]{23,}\.[\w-]{6}\.[\w-]{27}`), Severity: SeverityHigh, Category: CategoryToken, }, { ID: "discord-webhook", Name: "Discord Webhook URL", Description: "Discord webhook URL", Regex: regexp.MustCompile(`https://discord(?:app)?\.com/api/webhooks/[0-9]+/[A-Za-z0-9_-]+`), Severity: SeverityHigh, Category: CategoryCredential, }, // ============================================ // TELEGRAM (High) // ============================================ { ID: "telegram-bot-token", Name: "Telegram Bot Token", Description: "Telegram Bot API token", Regex: regexp.MustCompile(`\b[0-9]{8,10}:[A-Za-z0-9_-]{35}\b`), Severity: SeverityHigh, Category: CategoryToken, }, // ============================================ // SHOPIFY (High) // ============================================ { ID: "shopify-token", Name: "Shopify Access Token", Description: "Shopify private app or custom app token", Regex: regexp.MustCompile(`shpat_[a-fA-F0-9]{32}`), Severity: SeverityHigh, Category: CategoryToken, }, // ============================================ // HEROKU (High) // ============================================ { ID: "heroku-api-key", Name: "Heroku API Key", Description: "Heroku platform API key", Regex: regexp.MustCompile(`(?i)heroku.*['\"][0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}['\"]`), Severity: SeverityHigh, Category: CategoryAPIKey, }, } // genericFalsePositivePatterns are patterns that indicate false positives across all detections var genericFalsePositivePatterns = []*regexp.Regexp{ regexp.MustCompile(`^[xX]+$`), // All x's (placeholder) regexp.MustCompile(`^[0]+$`), // All zeros regexp.MustCompile(`(?i)example`), // Contains "example" regexp.MustCompile(`(?i)sample`), // Contains "sample" regexp.MustCompile(`(?i)dummy`), // Contains "dummy" regexp.MustCompile(`(?i)placeholder`), // Contains "placeholder" regexp.MustCompile(`(?i)your[_-]?(api[_-]?)?key`), // "your_key", "your_api_key", etc. regexp.MustCompile(`__[A-Z_]+__`), // Python dunder-like placeholders } // GetBuiltinPatterns returns all built-in secret detection patterns func GetBuiltinPatterns() []Pattern { return builtinPatterns } // IsFalsePositive checks if a match is a false positive func IsFalsePositive(match string, pattern *Pattern) bool { // Check pattern-specific false positives for _, fp := range pattern.FalsePositiveRegexes { if fp.MatchString(match) { return true } } // Check generic false positives for _, fp := range genericFalsePositivePatterns { if fp.MatchString(match) { return true } } return false }