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