Primitive validator for detecting hardcoded secrets and sensitive patterns in code
npm install @bernierllc/validators-secret-patternsPrimitive validator for detecting hardcoded secrets and sensitive patterns in code - API keys, tokens, passwords, private keys, database credentials, and high-entropy strings.
``bash`
npm install @bernierllc/validators-secret-patterns
- API Key Detection - AWS, GitHub, Google, Stripe, SendGrid, Twilio, Slack, NPM, and more
- High-Entropy String Detection - Identifies potential secrets based on entropy analysis
- JWT Token Detection - Detects hardcoded JSON Web Tokens
- Private Key Detection - RSA, SSH, PGP, EC, OpenSSH, and other private key formats
- Password Pattern Detection - Identifies hardcoded passwords in various formats
- Database Connection Strings - PostgreSQL, MySQL, MongoDB, Redis, SQL Server, Oracle
- Custom Pattern Support - Add your own secret detection patterns
- Configurable Detection - Enable/disable specific checks as needed
- High-Precision Matching - Minimizes false positives with smart filtering
`typescript
import { validateSecretPatterns } from '@bernierllc/validators-secret-patterns';
const code =
const awsKey = "AKIAIOSFODNN7EXAMPLE";
const password = "MySecretP@ssw0rd123";;
const problems = await validateSecretPatterns(code);
if (problems.length > 0) {
problems.forEach(problem => {
console.log(${problem.severity}: ${problem.message}); at line ${problem.location?.line}, column ${problem.location?.column}
console.log();`
});
}
`typescript
import { validateSecretPatterns } from '@bernierllc/validators-secret-patterns';
const problems = await validateSecretPatterns(sourceCode, {
// Entropy detection settings
minEntropyScore: 4.5, // Higher = stricter (0-8 scale)
minEntropyLength: 20, // Minimum length for entropy analysis
// Enable/disable specific checks
checkApiKeys: true,
checkEntropy: true,
checkJwtTokens: true,
checkPrivateKeys: true,
checkPasswords: true,
checkDatabaseStrings: true,
// Custom patterns
customPatterns: [
{
pattern: /CUSTOM-SECRET-\d+/g,
name: 'Custom Secret Format',
severity: 'error'
}
],
// Exclude known safe patterns (e.g., test data)
excludePatterns: [
/example\.com/,
/test-key-\d+/
]
});
`
`typescript
import { hasSecrets } from '@bernierllc/validators-secret-patterns';
if (await hasSecrets(code)) {
console.log('⚠️ Secrets detected in code!');
}
`
`typescript
import { getSecretCounts } from '@bernierllc/validators-secret-patterns';
const counts = await getSecretCounts(code);
console.log(Found ${counts.total} secrets:); - ${counts.apiKeys} API keys
console.log(); - ${counts.passwords} passwords
console.log(); - ${counts.privateKeys} private keys
console.log(); - ${counts.databaseStrings} database connections
console.log(); - ${counts.jwtTokens} JWT tokens
console.log(); - ${counts.entropy} high-entropy strings
console.log();`
`typescript
import { apiKeysRule, passwordsRule } from '@bernierllc/validators-secret-patterns';
import { createRuleContext } from '@bernierllc/validators-core';
const problems = [];
const context = createRuleContext(
'secret-patterns/api-keys',
{ excludePatterns: [/test-key/] },
utils,
{},
(p) => problems.push(p)
);
const validator = apiKeysRule.create(context);
await validator(sourceCode);
console.log(problems);
`
Validates content for hardcoded secrets and sensitive patterns.
Parameters:
- content (string): Content to validate (source code, configuration, etc.)options
- (object, optional): Validation optionsminEntropyScore
- (number, default: 4.5): Minimum entropy score (0-8)minEntropyLength
- (number, default: 20): Minimum length for entropy analysischeckApiKeys
- (boolean, default: true): Check for API keyscheckEntropy
- (boolean, default: true): Check for high-entropy stringscheckJwtTokens
- (boolean, default: true): Check for JWT tokenscheckPrivateKeys
- (boolean, default: true): Check for private keyscheckPasswords
- (boolean, default: true): Check for passwordscheckDatabaseStrings
- (boolean, default: true): Check for database connectionscustomPatterns
- (array, optional): Custom patterns to detectexcludePatterns
- (array, optional): Patterns to exclude/allowlistutils
- (SharedUtils, optional): Shared utilities from validators-utils
Returns: Promise - Array of validation problems
Quick check if content contains any secrets.
Parameters:
- content (string): Content to checkoptions
- (object, optional): Same as validateSecretPatterns
Returns: Promise - true if secrets detected
Get count of secrets by type.
Parameters:
- content (string): Content to analyzeoptions
- (object, optional): Same as validateSecretPatterns
Returns: Promise
Detects hardcoded API keys and tokens from various services.
Detects:
- AWS Access Keys (AKIA..., ASIA...)
- AWS Secret Keys
- GitHub Personal Access Tokens (ghp_, gho_, ghr_)
- Google API Keys (AIza...)
- Google OAuth Tokens (ya29.)
- Stripe API Keys (sk_live, pk_live)
- SendGrid API Keys (SG....)
- Twilio API Keys (SK...)
- Slack Tokens (xoxb-, xoxp-)
- Slack Webhooks
- Mailgun API Keys
- Mailchimp API Keys
- NPM Tokens (npm_...)
- Azure Storage Keys
- Heroku API Keys (UUID format)
- Generic API key patterns
Example:
`typescript`
// ❌ Detected
const awsKey = "AKIAIOSFODNN7EXAMPLE";
const githubToken = "ghp_1234567890abcdefghijklmnopqrstuv";
const stripeKey = "sk_live_1234567890abcdefghijklmn";
Detects high-entropy strings that may indicate hardcoded secrets.
Algorithm:
- Calculates Shannon entropy (0-8 scale)
- Requires mix of character types (uppercase, lowercase, numbers, special chars)
- Filters out common false positives (UUIDs, URLs, package names, hex colors)
Configuration:
- minEntropyScore (default: 4.5): Minimum entropy thresholdminEntropyLength
- (default: 20): Minimum string length
Example:
`typescript
// ⚠️ Detected (high entropy)
const secret = "aB3dEfGhIjKlMnOpQrStUvWxYz123456789";
// ✅ Not detected (UUID format)
const id = "550e8400-e29b-41d4-a716-446655440000";
// ✅ Not detected (URL)
const url = "https://api.example.com/v1/users";
`
Detects hardcoded JSON Web Tokens (JWT).
Detection:
- Validates three base64url segments separated by dots
- Decodes header to verify JWT format
- Extracts algorithm and token type
Example:
`typescript`
// ❌ Detected
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
Detects hardcoded private keys in various formats.
Detects:
- RSA Private Keys
- Generic Private Keys (PKCS#8)
- EC Private Keys (Elliptic Curve)
- DSA Private Keys
- OpenSSH Private Keys
- PGP/GPG Private Keys
- Encrypted Private Keys
Example:
`typescript-----BEGIN RSA PRIVATE KEY-----
// ❌ Detected
const privateKey =
MIIEpAIBAAKCAQEA0Z3VS5JJcds3xvn6bBHs6
-----END RSA PRIVATE KEY-----;`
Detects hardcoded passwords in various contexts.
Patterns:
- Variable assignments (password = "...")
- JSON/config files ("password": "...")
- Connection strings (password=...)
- Basic authentication headers
False Positive Filtering:
- Excludes common placeholders (password, your_password)
- Excludes environment variable references (${PASSWORD})
- Excludes single words and simple patterns
- Excludes example/test data
Example:
`typescript
// ❌ Detected
const password = "MySecretP@ssw0rd123";
{"password": "SecurePass123!"}
password=MySecretPass123
// ✅ Not detected (placeholders)
const password = "password";
const password = "${PASSWORD}";
const password = "example";
`
Detects database connection strings with embedded credentials.
Detects:
- PostgreSQL (postgresql://user:pass@host/db)
- MySQL (mysql://user:pass@host/db)
- MongoDB (mongodb://user:pass@host/db)
- Redis (redis://user:pass@host)
- SQL Server (Server=...;Password=...)
- Oracle (Data Source=...;Password=...)
- ODBC (DRIVER=...;PWD=...)
- Generic database URLs
False Positive Filtering:
- Excludes placeholder usernames/passwords
- Excludes environment variable references
- Excludes example domains (example.com, test.com)
Example:
`typescript
// ❌ Detected
const db = "postgresql://admin:secretpass123@localhost:5432/mydb";
const mongo = "mongodb://user:pass123@dbhost:27017/database";
Server=myserver;Database=mydb;Password=sqlpass123;
// ✅ Not detected (placeholders)
const db = "postgresql://username:password@localhost:5432/db";
const db = "postgresql://user:pass@example.com:5432/db";
`
Each validation problem includes:
`typescript`
interface Problem {
ruleId: string; // e.g., "secret-patterns/api-keys"
message: string; // Human-readable description
severity: 'error' | 'warn' | 'info' | 'off';
domain: 'security'; // Validation domain
location?: { // Optional location information
line?: number;
column?: number;
};
suggestion?: string; // How to fix the issue
fixable?: boolean; // Whether issue is auto-fixable
evidence?: { // Supporting evidence
snippet?: string; // Code snippet (with masking for sensitive data)
context?: Record
};
tags?: string[]; // Additional categorization
}
`typescript
import { validateSecretPatterns } from '@bernierllc/validators-secret-patterns';
import * as fs from 'fs';
import * as path from 'path';
async function checkForSecrets(filePaths: string[]): Promise
let hasIssues = false;
for (const filePath of filePaths) {
const content = fs.readFileSync(filePath, 'utf-8');
const problems = await validateSecretPatterns(content);
if (problems.length > 0) {
console.error(❌ Secrets detected in ${filePath}:); ${p.severity}: ${p.message} (line ${p.location?.line})
problems.forEach(p => {
console.error();
});
hasIssues = true;
}
}
return !hasIssues;
}
// Usage in pre-commit hook
const changedFiles = process.argv.slice(2);
const passed = await checkForSecrets(changedFiles);
process.exit(passed ? 0 : 1);
`
`typescript
import { validateSecretPatterns, getSecretCounts } from '@bernierllc/validators-secret-patterns';
import * as glob from 'glob';
import * as fs from 'fs';
async function scanRepository(): Promise
const files = glob.sync('*/.{ts,js,json,env}', {
ignore: ['node_modules/', 'dist/', '.git/**']
});
let totalSecrets = 0;
for (const file of files) {
const content = fs.readFileSync(file, 'utf-8');
const counts = await getSecretCounts(content);
if (counts.total > 0) {
console.log(⚠️ ${file}: ${counts.total} secrets);
totalSecrets += counts.total;
}
}
if (totalSecrets > 0) {
console.error(\n❌ FAIL: Found ${totalSecrets} hardcoded secrets);
process.exit(1);
} else {
console.log('\n✅ PASS: No secrets detected');
}
}
scanRepository().catch(console.error);
`
`typescript
import { validateSecretPatterns } from '@bernierllc/validators-secret-patterns';
async function lintDocument(document: TextDocument): Promise
const problems = await validateSecretPatterns(document.getText(), {
// Adjust sensitivity for IDE (fewer false positives)
minEntropyScore: 5.0,
checkEntropy: false // Disable in IDE to reduce noise
});
return problems.map(problem => ({
severity: problem.severity === 'error'
? DiagnosticSeverity.Error
: DiagnosticSeverity.Warning,
range: {
start: { line: problem.location?.line || 0, character: problem.location?.column || 0 },
end: { line: problem.location?.line || 0, character: (problem.location?.column || 0) + 10 }
},
message: problem.message,
source: 'secret-patterns',
code: problem.ruleId
}));
}
`
`typescript
import { validateSecretPatterns } from '@bernierllc/validators-secret-patterns';
const problems = await validateSecretPatterns(code, {
customPatterns: [
// Organization-specific secret format
{
pattern: /ACME-API-[A-Z0-9]{32}/g,
name: 'ACME Corp API Key',
severity: 'error'
},
// Internal service tokens
{
pattern: /internal_token_[a-f0-9]{40}/g,
name: 'Internal Service Token',
severity: 'error'
},
// Legacy credential format
{
pattern: /legacy_cred=[A-Za-z0-9+/=]{24,}/g,
name: 'Legacy Credential',
severity: 'warn'
}
]
});
`
`typescript
import { validateSecretPatterns } from '@bernierllc/validators-secret-patterns';
const problems = await validateSecretPatterns(code, {
excludePatterns: [
// Test/example keys (documented in README)
/AKIAIOSFODNN7EXAMPLE/,
/test-key-[a-z0-9]+/i,
// Known public demo tokens
/demo-token-12345/,
// Development environment keys (non-production)
/dev-api-key-/i
]
});
`
This package follows the BernierLLC Validators Principles:
- Pure Validation Functions - Returns structured problems, never throws
- Atomic Primitives - Each rule has single responsibility
- Tool-Agnostic - Works in CLI, web apps, CI/CD, IDE plugins
- Evidence-Rich Results - Provides actionable debugging information
- Composable - Can be combined with other validators
- @bernierllc/validators-security - Comprehensive security validation@bernierllc/validators-code-quality
- - Code quality and security checks
- Custom security scanning tools
This is a primitive validator that returns structured problem arrays. Logging is handled by the consumer application. The validator uses @bernierllc/validators-core for structured problem reporting, which can be integrated with @bernierllc/logger by the consuming application if needed.
- Full TypeDoc API documentation generated
- Markdown documentation exported
- Format: markdown, typedoc, jsdoc
This is a primitive validator with no service discovery requirements. The validator uses @bernierllc/neverhub-adapter pattern through the validators-core framework, but direct NeverHub integration (detectNeverHub) is not needed for atomic validation primitives. Service orchestration and discovery are handled at higher levels (domain validators, validator runners).
- Sub-50ms validation for typical source files (< 10KB)
- Parallel execution of independent rules
- Smart filtering to minimize false positives
- Memory efficient - Streams through content without full AST
1. Use Environment Variables
`typescript
// ✅ Good
const apiKey = process.env.API_KEY;
// ❌ Bad
const apiKey = "AKIAIOSFODNN7EXAMPLE";
`
2. Use Secret Management Systems
- AWS Secrets Manager
- Azure Key Vault
- HashiCorp Vault
- Google Secret Manager
3. Implement Pre-commit Hooks
- Scan all changed files before commit
- Block commits containing secrets
- Provide clear remediation guidance
4. CI/CD Integration
- Scan entire repository on each build
- Fail builds if secrets detected
- Generate security reports
5. Developer Training
- Educate team about secret detection
- Document proper secret management
- Regular security awareness training
If secrets are detected:
1. Rotate the Secret - Immediately invalidate and regenerate
2. Remove from History - Use git filter-branch or BFG Repo-Cleaner
3. Update Code - Replace with environment variable or secret management
4. Review Access Logs - Check if compromised secret was accessed
5. Document Incident - Record what happened and how it was resolved
This package includes comprehensive test coverage:
`bash``
npm test # Run tests in watch mode
npm run test:run # Run tests once
npm run test:coverage # Run tests with coverage report
Coverage Requirements:
- Branches: 90%+
- Functions: 90%+
- Lines: 90%+
- Statements: 90%+
- @bernierllc/validators-core - Core validator types and utilities
- @bernierllc/validators-runner - Execute validators with policies
- @bernierllc/validators-reporters - Format validation results
- @bernierllc/validators-security - Comprehensive security validation
Copyright (c) 2025 Bernier LLC. All rights reserved.