lunx.docs
DocsSecuritySecret Scanning

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

ProviderPatternSeverity
AWS Access KeyAKIA[0-9A-Z]{16}Critical
GitHub PATghp_[a-zA-Z0-9]{36}Critical
Stripe Secret Keysk_live_[a-zA-Z0-9]{24}Critical
Stripe Test Keysk_test_[a-zA-Z0-9]{24}High
Slack Bot Tokenxoxb-[0-9]{11}-...High
SendGrid API KeySG\.[a-zA-Z0-9]{22}\...High
JWTeyJ[a-zA-Z0-9_-]{10,}\.[...]{2}Moderate
RSA Private Key-----BEGIN RSA PRIVATE KEY-----Critical
Generic High EntropyShannon entropy > 4.5 on string ≥ 20 charsModerate

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