Secret Scanning
Lunx automatically scans all source files, environment files, and config for leaked credentials before every build — catching secrets before they reach your bundle or git history.
How it works
The Lunx secret scanner runs in the Rust compiler core using two complementary detection strategies:
- Pattern matching — 200+ regexes covering all major credential formats (AWS, GitHub, Stripe, Slack, Twilio, SendGrid, etc.)
- Shannon entropy analysis — detects high-entropy strings that look like API keys or tokens, even without a known prefix pattern
The scanner runs in parallel across all source files using Rust threads, completing a 1,000-file scan in under 50ms.
Detected secret types
| Provider | Pattern | Severity |
|---|---|---|
| AWS Access Key | AKIA[0-9A-Z]{16} | Critical |
| GitHub PAT | ghp_[a-zA-Z0-9]{36} | Critical |
| Stripe Secret Key | sk_live_[a-zA-Z0-9]{24} | Critical |
| Stripe Test Key | sk_test_[a-zA-Z0-9]{24} | High |
| Slack Bot Token | xoxb-[0-9]{11}-... | High |
| SendGrid API Key | SG\.[a-zA-Z0-9]{22}\... | High |
| JWT | eyJ[a-zA-Z0-9_-]{10,}\.[...]{2} | Moderate |
| RSA Private Key | -----BEGIN RSA PRIVATE KEY----- | Critical |
| Generic High Entropy | Shannon entropy > 4.5 on string ≥ 20 chars | Moderate |
Running a scan
bash
# Manual scan of all files lunx security scan # Output on a clean project: 🔍 Secret scan — lunx v1.0.0 Scanning 84 files across 12 directories... ✓ 0 secrets detected (47ms) # Output when a secret is found: 🔍 Secret scan — lunx v1.0.0 Scanning 84 files... ✗ CRITICAL: AWS Access Key detected File: src/services/upload.ts:14 Match: AKIAIOSFODNN7EXAMPLE → Remove this key and rotate it immediately
Configuration
typescriptlunx.config.ts
export default defineConfig({ security: { scanSecrets: true, // Exclude specific paths from scanning excludePaths: [ './test/fixtures/**', './mock-data/**', './docs/examples/**', ], // Add custom patterns to detect (regex strings) customPatterns: [ 'MY_COMPANY_[A-Z0-9]{32}', // internal token format ], // Fail the build on any secret found (default: true) failOnSecrets: true, } })
Recommended .gitignore additions
bash.gitignore
# Never commit these files .env .env.local .env.production .env.*.local *.pem *.key secrets/
Rotate compromised credentials immediately
If the scanner finds a secret that was ever committed to git, assume it is compromised — git history is permanent. Rotate the credential immediately with the issuing provider, then use
git filter-branch or git-filter-repo to purge the history.Using environment variables safely
bash.env
# SAFE: prefixed with LUNX_PUBLIC_ — exposed to browser bundle LUNX_PUBLIC_API_URL=https://api.example.com LUNX_PUBLIC_APP_NAME=My App # SAFE: no prefix — server-side only, never bundled DATABASE_URL=postgres://user:pass@localhost/db STRIPE_SECRET_KEY=sk_live_... AWS_SECRET_ACCESS_KEY=...
typescript
// In browser code — only LUNX_PUBLIC_ vars are available const apiUrl = import.meta.env.LUNX_PUBLIC_API_URL // This throws a compile-time error — Lunx blocks it: const secret = import.meta.env.STRIPE_SECRET_KEY // ✗ not exposed