@llm-dev-ops/shield-sdk
Version:
Enterprise-grade SDK for securing Large Language Model applications
119 lines • 5.45 kB
JavaScript
import { BaseScanner } from './base.js';
/**
* Built-in secret patterns
*/
const SECRET_PATTERNS = {
aws: [
{ pattern: /AKIA[0-9A-Z]{16}/g, type: 'AWS Access Key ID', severity: 'critical' },
{ pattern: /aws[_-]?secret[_-]?access[_-]?key["']?\s*[:=]\s*["']?[A-Za-z0-9/+=]{40}/gi, type: 'AWS Secret Access Key', severity: 'critical' },
],
github: [
{ pattern: /ghp_[a-zA-Z0-9]{36}/g, type: 'GitHub Personal Access Token', severity: 'high' },
{ pattern: /gho_[a-zA-Z0-9]{36}/g, type: 'GitHub OAuth Token', severity: 'high' },
{ pattern: /ghs_[a-zA-Z0-9]{36}/g, type: 'GitHub App Token', severity: 'high' },
{ pattern: /ghr_[a-zA-Z0-9]{36}/g, type: 'GitHub Refresh Token', severity: 'high' },
{ pattern: /github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}/g, type: 'GitHub Fine-grained PAT', severity: 'high' },
],
stripe: [
{ pattern: /sk_live_[0-9a-zA-Z]{24,}/g, type: 'Stripe Live Secret Key', severity: 'critical' },
{ pattern: /sk_test_[0-9a-zA-Z]{24,}/g, type: 'Stripe Test Secret Key', severity: 'medium' },
{ pattern: /pk_live_[0-9a-zA-Z]{24,}/g, type: 'Stripe Live Publishable Key', severity: 'low' },
{ pattern: /rk_live_[0-9a-zA-Z]{24,}/g, type: 'Stripe Restricted Key', severity: 'high' },
],
openai: [
{ pattern: /sk-[a-zA-Z0-9]{48}/g, type: 'OpenAI API Key', severity: 'high' },
{ pattern: /sk-proj-[a-zA-Z0-9]{48}/g, type: 'OpenAI Project API Key', severity: 'high' },
],
anthropic: [
{ pattern: /sk-ant-[a-zA-Z0-9-]{32,}/g, type: 'Anthropic API Key', severity: 'high' },
],
slack: [
{ pattern: /xox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24}/g, type: 'Slack Token', severity: 'high' },
{ pattern: /https:\/\/hooks\.slack\.com\/services\/T[a-zA-Z0-9_]{8,}\/B[a-zA-Z0-9_]{8,}\/[a-zA-Z0-9_]{24}/g, type: 'Slack Webhook URL', severity: 'high' },
],
google: [
{ pattern: /AIza[0-9A-Za-z\-_]{35}/g, type: 'Google API Key', severity: 'high' },
{ pattern: /[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com/g, type: 'Google OAuth Client ID', severity: 'medium' },
],
generic: [
{ pattern: /api[_-]?key["']?\s*[:=]\s*["']?[a-zA-Z0-9]{32,}/gi, type: 'Generic API Key', severity: 'medium' },
{ pattern: /secret["']?\s*[:=]\s*["']?[a-zA-Z0-9]{32,}/gi, type: 'Generic Secret', severity: 'medium' },
{ pattern: /password["']?\s*[:=]\s*["']?[^\s'"]{8,}/gi, type: 'Password', severity: 'high' },
{ pattern: /token["']?\s*[:=]\s*["']?[a-zA-Z0-9-_]{20,}/gi, type: 'Generic Token', severity: 'medium' },
],
'private-key': [
{ pattern: /-----BEGIN (RSA |EC |OPENSSH |PGP |DSA )?PRIVATE KEY-----/g, type: 'Private Key', severity: 'critical' },
{ pattern: /-----BEGIN ENCRYPTED PRIVATE KEY-----/g, type: 'Encrypted Private Key', severity: 'high' },
],
jwt: [
{ pattern: /eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*/g, type: 'JWT Token', severity: 'high' },
],
};
/**
* Scanner for detecting secrets and credentials
*/
export class SecretsScanner extends BaseScanner {
name = 'secrets';
patterns;
redact;
constructor(config = {}) {
super();
this.redact = config.redact ?? true;
// Build pattern list based on config
const enabledTypes = config.secretTypes ?? Object.keys(SECRET_PATTERNS);
this.patterns = [];
for (const type of enabledTypes) {
if (SECRET_PATTERNS[type]) {
this.patterns.push(...SECRET_PATTERNS[type]);
}
}
// Add custom patterns
if (config.customPatterns) {
for (const custom of config.customPatterns) {
this.patterns.push({
pattern: custom.pattern,
type: custom.type,
severity: custom.severity ?? 'medium',
});
}
}
}
async scan(text) {
const startTime = performance.now();
const entities = [];
const riskFactors = [];
const foundTypes = new Set();
for (const { pattern, type, severity } of this.patterns) {
const regex = new RegExp(pattern.source, pattern.flags);
let match;
while ((match = regex.exec(text)) !== null) {
entities.push({
entityType: 'secret',
text: this.redact ? this.maskSecret(match[0]) : match[0],
start: match.index,
end: match.index + match[0].length,
confidence: 0.95,
});
if (!foundTypes.has(type)) {
foundTypes.add(type);
riskFactors.push({
category: 'secret',
description: `Detected ${type}`,
severity,
confidence: 0.95,
metadata: { secretType: type },
});
}
}
}
const durationMs = performance.now() - startTime;
return this.createResult(text, entities, riskFactors, durationMs);
}
maskSecret(secret) {
if (secret.length <= 8) {
return '****';
}
return secret.substring(0, 4) + '****' + secret.substring(secret.length - 4);
}
}
//# sourceMappingURL=secrets.js.map