1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use regex::Regex;
pub struct RedactionEngine {
patterns: Vec<Regex>,
}
impl RedactionEngine {
pub fn new() -> Self {
Self {
patterns: initialize_sensitive_patterns(),
}
}
pub fn redact_sensitive_content(&self, content: &str) -> String {
let mut redacted_content = content.to_string();
for pattern in &self.patterns {
redacted_content = pattern.replace_all(&redacted_content, "REDACTED").to_string();
}
redacted_content
}
}
impl Default for RedactionEngine {
fn default() -> Self {
Self::new()
}
}
fn initialize_sensitive_patterns() -> Vec<Regex> {
let patterns = vec![
// ==== OPENAI & AI PROVIDERS ====
r"sk-proj-[A-Za-z0-9_-]+", // OpenAI project-scoped key
r"dtn_[A-Za-z0-9_]+", // Daytona API key
r"e2b_[A-Za-z0-9_]+", // E2B API key
r"sk-ant-[A-Za-z0-9_-]+", // Anthropic API key
r"sk-or-[A-Za-z0-9_-]+", // OpenAI org-scoped key
r"sk-[A-Za-z0-9_-]+", // OpenAI generic secret
r"gsk_[A-Za-z0-9_-]+", // Google Generative AI Studio key
r"xai-[A-Za-z0-9_-]+", // xAI key
// ==== GITHUB ====
r"ghp_[A-Za-z0-9_]{36}", // GitHub PAT (classic)
r"gho_[A-Za-z0-9_]{36}", // GitHub OAuth token
r"ghs_[A-Za-z0-9_]{36}", // GitHub App server-to-server
r"ghu_[A-Za-z0-9_]{36}", // GitHub App user-to-server
r"ghr_[A-Za-z0-9_]{36}", // GitHub refresh token
r"github_pat_[A-Za-z0-9_]{22}_[A-Za-z0-9_]{59}", // GitHub fine-grained PAT
// ==== GITLAB ====
r"glpat-[A-Za-z0-9_-]+", // GitLab PAT
// ==== AWS ====
r"AKIA[0-9A-Z]{16}", // AWS access key ID (long-lived)
r"ASIA[0-9A-Z]{16}", // AWS temporary access key ID
r"(?i)(aws_)?secret(access)?(_)?key\s*[:=]\s*[A-Za-z0-9/+=]{35,}", // AWS secret key
// ==== GOOGLE API KEYS ====
r"AIza[0-9A-Za-z-_]{35}", // Google API key (common AIza prefix)
r"ya29\.[0-9A-Za-z-_]+", // Google OAuth access token
r"GOCSPX-[A-Za-z0-9-_]+", // Google OAuth client secret
// ==== SLACK ====
r"xoxb-[A-Za-z0-9-]+-[A-Za-z0-9-]+-[A-Za-z0-9-]+", // Slack bot token
r"xoxp-[A-Za-z0-9-]+-[A-Za-z0-9-]+-[A-Za-z0-9-]+", // Slack user token
r"xoxa-[A-Za-z0-9-]+-[A-Za-z0-9-]+-[A-Za-z0-9-]+", // Slack workspace token
r"xapp-1-[A-Z0-9-]+-[0-9]+-[A-Za-z0-9]+", // Slack App level token
// ==== STRIPE ====
r"sk_live_[0-9a-zA-Z]+", // Stripe live secret key
r"sk_test_[0-9a-zA-Z]+", // Stripe test secret key
r"rk_live_[0-9a-zA-Z]+", // Stripe restricted key live
r"rk_test_[0-9a-zA-Z]+", // Stripe restricted key test
r"whsec_[A-Za-z0-9]+", // Stripe webhook secret
// ==== TWILIO ====
r"AC[0-9a-fA-F]{32}", // Twilio Account SID
r"SK[0-9a-fA-F]{32}", // Twilio API Key SID
// ==== SENDGRID / MAIL PROVIDERS ====
r"SG\.[A-Za-z0-9_\-\.]{66}", // SendGrid API key
r"key-[0-9a-f]{32}", // Mailgun API key (specific with 'key-' prefix)
r"xkeysib-[A-Za-z0-9]{64}-[A-Za-z0-9]{16}", // SendInBlue API key
// ==== PAYMENT / CREDIT CARDS ====
r"\b4[0-9]{12}(?:[0-9]{3})?\b", // Visa (no spaces)
r"\b4[0-9]{3}[\s-]?[0-9]{4}[\s-]?[0-9]{4}[\s-]?[0-9]{4}\b", // Visa (with spaces/dashes)
r"\b5[1-5][0-9]{14}\b", // MasterCard (no spaces)
r"\b5[1-5][0-9]{2}[\s-]?[0-9]{4}[\s-]?[0-9]{4}[\s-]?[0-9]{4}\b", // MasterCard (with spaces/dashes)
r"\b3[47][0-9]{13}\b", // AmEx (no spaces)
r"\b3[47][0-9]{2}[\s-]?[0-9]{6}[\s-]?[0-9]{5}\b", // AmEx (with spaces/dashes)
r"\b6(?:011|5[0-9]{2})[0-9]{12}\b", // Discover (no spaces)
r"\b6(?:011|5[0-9]{2})[\s-]?[0-9]{4}[\s-]?[0-9]{4}[\s-]?[0-9]{4}\b", // Discover (with spaces/dashes)
// ==== EMAIL ADDRESSES ====
r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b", // Email addresses
// ==== DATABASE CONNECTION STRINGS - With passwords ====
r"\bpostgres(?:ql)?://[A-Za-z0-9_%+.-]+:[^@\s]{1,}@[^\s]+/[A-Za-z0-9_.-]+",
r"\bmongodb(?:\+srv)?://[A-Za-z0-9_%+.-]+:[^@\s]{1,}@[^\s]+/[A-Za-z0-9_.-]+",
r"\bmysql://[A-Za-z0-9_%+.-]+:[^@\s]{1,}@[^\s]+/[A-Za-z0-9_.-]+",
r"\bredis://[A-Za-z0-9_%+.-]+:[^@\s]{1,}@[A-Za-z0-9_.:-]+",
// ==== JWT TOKENS ====
r"\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b", // JWT tokens
// ==== SSH KEYS ====
r"-----BEGIN (?:RSA|DSA|EC|OPENSSH) PRIVATE KEY-----[\s\S]+?-----END (?:RSA|DSA|EC|OPENSSH) PRIVATE KEY-----",
// ==== OTHER SPECIFIC API KEYS ====
r"\bDD_API_KEY\b[^\n]{0,40}[:=]\s*[0-9a-f]{32}\b", // Datadog
r"\bDD_APP_KEY\b[^\n]{0,40}[:=]\s*[0-9a-f]{40}\b", // Datadog
r"NRAK-[A-Z0-9]{27}", // New Relic ingest key
r"NRAL-[A-Z0-9]{27}", // New Relic license key
r"shpat_[a-f0-9]{32}", // Shopify private app access token
r"shpss_[a-f0-9]{32}", // Shopify shared secret
r"npm_[A-Za-z0-9]{36}", // npm access token
r"\bpypi-AgENdGV\w{20,}\b", // PyPI token
r"EAA[A-Za-z0-9]+", // Facebook access token
r"\bBearer\s+AAAAAAAA[A-Za-z0-9%\-_]+\b", // Twitter bearer token
r"lin_[A-Za-z0-9]{40}", // Linear API key
r"secret_[A-Za-z0-9]{43}", // Notion token
r"CFPAT-[A-Za-z0-9_-]+", // Contentful API token
r"sdk-[A-Za-z0-9_-]+", // LaunchDarkly SDK key (made more specific)
r"mob-[A-Za-z0-9_-]+", // LaunchDarkly Mobile key (made more specific)
r"r8_[A-Za-z0-9]+", // Replicate API token
// ==== CRYPTO WALLETS ====
r"\b0x[a-fA-F0-9]{40}\b", // Ethereum address
r"\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b", // Bitcoin (legacy)
r"\bbc1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{11,71}\b", // Bitcoin Bech32
// ==== SPECIFIC SECRET PATTERNS WITH CONTEXT ====
r"(?i)\b(SECRET_KEY|API_SECRET|CLIENT_SECRET|PRIVATE_KEY)\b\s*[:=]\s*[A-Za-z0-9\-_.+/=]+",
r"(?i)\b(password|passwd|pwd)\b\s*[:=]\s*[^\s]+",
r"(?i)\b(api_key|apikey|api_token|access_token)\b\s*[:=]\s*[A-Za-z0-9\-_.]+",
];
patterns.into_iter()
.filter_map(|pattern| Regex::new(pattern).ok())
.collect()
}