@link-foundation/sensitive-data-sanitizer 0.19.3 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +22 -2
- package/bin/sensitive-data-sanitizer.js +50 -28
- package/docs/API.md +355 -16
- package/docs/COVERAGE.md +19 -9
- package/docs/RULES.md +218 -0
- package/examples/second-pass-placeholders.mjs +28 -0
- package/package.json +12 -3
- package/src/allow-list.js +93 -0
- package/src/confidence.js +24 -9
- package/src/context.js +287 -40
- package/src/credential-spans.js +180 -0
- package/src/credentials-entry.d.ts +23 -0
- package/src/credentials-entry.js +62 -0
- package/src/credentials.js +51 -0
- package/src/crypto-addresses.js +74 -0
- package/src/detection.js +87 -41
- package/src/document-person-cues.js +1 -1
- package/src/encoded.js +137 -51
- package/src/encrypt.js +95 -0
- package/src/engines.js +33 -10
- package/src/entities.js +4 -3
- package/src/exempt.js +72 -0
- package/src/fake-memory.js +32 -0
- package/src/fake.js +33 -29
- package/src/features.js +29 -0
- package/src/files.js +57 -12
- package/src/gitleaks.js +82 -27
- package/src/html-tags.js +8 -0
- package/src/identifier-detector.js +36 -0
- package/src/identity-types.js +63 -0
- package/src/identity.js +3 -47
- package/src/index.d.ts +157 -3
- package/src/index.js +13 -0
- package/src/known.js +33 -15
- package/src/national-checks.js +209 -0
- package/src/national.js +310 -92
- package/src/pattern-detector.js +219 -0
- package/src/personal-context.js +3 -2
- package/src/personal-evidence.js +233 -0
- package/src/personal-features.js +39 -0
- package/src/personal.js +66 -10
- package/src/placeholder-types.js +154 -4
- package/src/placeholders.js +127 -45
- package/src/projection.js +78 -26
- package/src/proper-names.js +48 -5
- package/src/prose-words.js +120 -0
- package/src/record-worker.js +1 -0
- package/src/rule-catalog.js +426 -0
- package/src/rules.js +8 -0
- package/src/sanitizer.js +133 -23
- package/src/sarif.js +127 -0
- package/src/stream-worker.js +1 -0
- package/src/strict-attributes.js +48 -4
- package/src/strict.js +1 -1
- package/src/structured.js +2 -0
- package/src/token-checksum.js +49 -0
- package/src/transforms.js +146 -33
- package/src/vendor/betterleaks/LICENSE +21 -0
- package/src/vendor/betterleaks/provenance.json +11 -0
- package/src/vendor/betterleaks/rules-0.json +463 -0
- package/src/vendor/betterleaks/rules-1.json +454 -0
- package/src/vendor/betterleaks/rules-2.json +461 -0
- package/src/vendor/betterleaks/rules-3.json +455 -0
- package/src/vendor/betterleaks/rules-4.json +483 -0
- package/src/vendor/betterleaks/rules-5.json +35 -0
- package/src/vendor/entities/aws.json +1 -1
- package/src/vendor/entities/azure.json +6 -2
- package/src/vendor/entities/google.json +2 -1
- package/src/vocabulary.js +27 -1
- package/src/worker-options.js +1 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "slack-session-cookie",
|
|
4
|
+
"description": "Detected a Slack session cookie (xoxd-), which authenticates browser and desktop sessions across all of a user's workspaces.",
|
|
5
|
+
"regex": "(xoxd-[\\w\\/\\\\+-]{100,}={0,2})(?:[^\\w\\/+=-]|\\z)",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"xoxd-"
|
|
8
|
+
],
|
|
9
|
+
"confidence": "high",
|
|
10
|
+
"filter": "entropy(finding[\"secret\"]) <= 3.5\n",
|
|
11
|
+
"entropy": 3.5,
|
|
12
|
+
"entropyInclusive": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "slack-session-token",
|
|
16
|
+
"description": "Detected a Slack client session token (xoxc-), which provides full user-level API access when paired with a session cookie.",
|
|
17
|
+
"regex": "xoxc-\\d{9,15}-\\d{9,15}-\\d{9,15}-[a-f0-9]{64}\\b",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"xoxc-"
|
|
20
|
+
],
|
|
21
|
+
"confidence": "high",
|
|
22
|
+
"filter": "entropy(finding[\"secret\"]) <= 3.5\n",
|
|
23
|
+
"entropy": 3.5,
|
|
24
|
+
"entropyInclusive": true
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "snowflake-programmatic-access-token.1",
|
|
28
|
+
"description": "Snowflake programmatic access token.",
|
|
29
|
+
"regex": "(?i:(?:(?:snowflake[_. -]*(?:programmatic[_. -]*)?(?:access[_. -]*)?token|sf[_. -]*token))(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3})(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([A-Za-z0-9_-]{100,500})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
30
|
+
"keywords": [
|
|
31
|
+
"snowflake",
|
|
32
|
+
"sf_token"
|
|
33
|
+
],
|
|
34
|
+
"confidence": "high",
|
|
35
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
36
|
+
"entropy": 3.5
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "sslmate-api-key.1",
|
|
40
|
+
"description": "SSLMate API key.",
|
|
41
|
+
"regex": "(?i:(?:sslmate(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3})(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([A-Za-z0-9]{36})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
42
|
+
"keywords": [
|
|
43
|
+
"sslmate"
|
|
44
|
+
],
|
|
45
|
+
"confidence": "high",
|
|
46
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
47
|
+
"entropy": 3.5
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "stability-ai-api-key",
|
|
51
|
+
"description": "Detected a Stability AI API Key, which may expose AI image generation services to unauthorized access.",
|
|
52
|
+
"regex": "(?i)(?:stability)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}(sk-[A-Za-z0-9]{48})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
53
|
+
"keywords": [
|
|
54
|
+
"stability"
|
|
55
|
+
],
|
|
56
|
+
"confidence": "medium",
|
|
57
|
+
"filter": "entropy(finding[\"secret\"]) <= 3.5\n",
|
|
58
|
+
"entropy": 3.5,
|
|
59
|
+
"entropyInclusive": true
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "supabase-management-token",
|
|
63
|
+
"description": "Detected a Supabase Management Token, which may allow unauthorized access to Supabase organizations and projects.",
|
|
64
|
+
"regex": "\\b(sbp_[a-z0-9_-]{40})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
65
|
+
"keywords": [
|
|
66
|
+
"sbp_"
|
|
67
|
+
],
|
|
68
|
+
"confidence": "high",
|
|
69
|
+
"filter": "entropy(finding[\"secret\"]) <= 3.5\n|| !matchesAny(finding[\"secret\"], [`^sbp_[a-z0-9_-]*[0-9][a-z0-9_-]*[0-9][a-z0-9_-]*$`])\n",
|
|
70
|
+
"entropy": 3.5,
|
|
71
|
+
"entropyInclusive": true,
|
|
72
|
+
"require": [
|
|
73
|
+
"^sbp_[a-z0-9_-]*[0-9][a-z0-9_-]*[0-9][a-z0-9_-]*$"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "supabase-project-api-key",
|
|
78
|
+
"description": "Detected a Supabase Project API Key, which may expose project data through Supabase APIs when paired with a project URL.",
|
|
79
|
+
"regex": "\\b(sb_secret_[A-Za-z0-9_-]{31})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
80
|
+
"keywords": [
|
|
81
|
+
"sb_secret_"
|
|
82
|
+
],
|
|
83
|
+
"confidence": "high",
|
|
84
|
+
"filter": "entropy(finding[\"secret\"]) <= 4.0\n",
|
|
85
|
+
"entropy": 4.0,
|
|
86
|
+
"entropyInclusive": true
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "tableau-personal-access-token.1",
|
|
90
|
+
"description": "Tableau personal access token.",
|
|
91
|
+
"regex": "(?:^|[^A-Za-z0-9+/])([A-Za-z0-9+/]{22}==:[A-Za-z0-9]{32})\\b",
|
|
92
|
+
"keywords": [
|
|
93
|
+
"tableau"
|
|
94
|
+
],
|
|
95
|
+
"confidence": "high",
|
|
96
|
+
"filter": "entropy(finding[\"secret\"]) < 3.5\n",
|
|
97
|
+
"entropy": 3.5
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "tailscale-api-key.1",
|
|
101
|
+
"description": "Tailscale API access token.",
|
|
102
|
+
"regex": "\\b(tskey-api-[A-Za-z0-9_-]{20,36})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
103
|
+
"keywords": [
|
|
104
|
+
"tskey-api-"
|
|
105
|
+
],
|
|
106
|
+
"confidence": "high",
|
|
107
|
+
"filter": "entropy(finding[\"secret\"]) < 3.0\n",
|
|
108
|
+
"entropy": 3.0
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "telnyx-api-v2-key.1",
|
|
112
|
+
"description": "Telnyx API v2 key.",
|
|
113
|
+
"regex": "(?i:(?:telnyx(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3})(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}(KEY[0-9A-Za-z_-]{55})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
114
|
+
"keywords": [
|
|
115
|
+
"telnyx"
|
|
116
|
+
],
|
|
117
|
+
"confidence": "high",
|
|
118
|
+
"filter": "entropy(finding[\"secret\"]) < 3.5\n",
|
|
119
|
+
"entropy": 3.5
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"id": "temporal-cloud-api-key.1",
|
|
123
|
+
"description": "Temporal Cloud API key.",
|
|
124
|
+
"regex": "\\b(eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]*Y2NvdW50X2lk[A-Za-z0-9_-]*InRlbXBvcmFsLmlv[A-Za-z0-9_-]*(?:ICJrZXlfaWQiOi|a2V5X2lk|rZXlfaWQi)[A-Za-z0-9_-]{20,}\\.[A-Za-z0-9_-]{20,})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
125
|
+
"keywords": [
|
|
126
|
+
"inrlbxbvcmfslmlv"
|
|
127
|
+
],
|
|
128
|
+
"confidence": "high",
|
|
129
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.2\n|| !filter.matchesAny(finding[\"secret\"], [\"^(?:[^0-9]*[0-9]){3}\"])\n",
|
|
130
|
+
"entropy": 3.2,
|
|
131
|
+
"require": [
|
|
132
|
+
"^(?:[^0-9]*[0-9]){3}"
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "thunderstore-api-token.1",
|
|
137
|
+
"description": "Thunderstore API token.",
|
|
138
|
+
"regex": "\\b(tss_[A-Za-z0-9_-]{20,80})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
139
|
+
"keywords": [
|
|
140
|
+
"tss_"
|
|
141
|
+
],
|
|
142
|
+
"confidence": "high",
|
|
143
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5\n|| !filter.matchesAny(finding[\"secret\"], [\"^(?:[^0-9]*[0-9]){2}\"])\n",
|
|
144
|
+
"entropy": 3.5,
|
|
145
|
+
"require": [
|
|
146
|
+
"^(?:[^0-9]*[0-9]){2}"
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"id": "togetherai-api-key",
|
|
151
|
+
"description": "Detected a Together.ai API Key, which may expose access to open-source AI models and inference services.",
|
|
152
|
+
"regex": "(?i)\\b(tgp_v1_[A-Za-z0-9_-]{43})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
153
|
+
"keywords": [
|
|
154
|
+
"tgp_v1_"
|
|
155
|
+
],
|
|
156
|
+
"confidence": "high",
|
|
157
|
+
"filter": "entropy(finding[\"secret\"]) <= 3.0\n",
|
|
158
|
+
"entropy": 3.0,
|
|
159
|
+
"entropyInclusive": true
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"id": "unkey-root-key.1",
|
|
163
|
+
"description": "Unkey administrative root key.",
|
|
164
|
+
"regex": "\\b(unkey_[A-Za-z0-9]{20,32})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
165
|
+
"keywords": [
|
|
166
|
+
"unkey_"
|
|
167
|
+
],
|
|
168
|
+
"confidence": "high",
|
|
169
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5\n|| !filter.matchesAny(finding[\"secret\"], [\"[0-9]\"])\n|| !filter.matchesAny(finding[\"secret\"], [\"[A-Z]\"])\n|| !filter.matchesAny(finding[\"secret\"], [\"[a-z]\"])\n",
|
|
170
|
+
"entropy": 3.5,
|
|
171
|
+
"require": [
|
|
172
|
+
"[0-9]",
|
|
173
|
+
"[A-Z]",
|
|
174
|
+
"[a-z]"
|
|
175
|
+
]
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"id": "upcloud-api-token",
|
|
179
|
+
"description": "Identified an UpCloud API token, which may expose cloud infrastructure resources to unauthorized access.",
|
|
180
|
+
"regex": "\\b(ucat_[0-9A-Za-z]{24,32})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
181
|
+
"keywords": [
|
|
182
|
+
"ucat_"
|
|
183
|
+
],
|
|
184
|
+
"confidence": "high",
|
|
185
|
+
"filter": "entropy(finding[\"secret\"]) < 3.0\n",
|
|
186
|
+
"entropy": 3.0
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"id": "upstage-api-key",
|
|
190
|
+
"description": "Detected an Upstage AI API key, which may expose Solar language models and document AI services to unauthorized access.",
|
|
191
|
+
"regex": "(?i)(?:upstage)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([A-Za-z0-9]{40,50})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
192
|
+
"keywords": [
|
|
193
|
+
"upstage"
|
|
194
|
+
],
|
|
195
|
+
"confidence": "medium",
|
|
196
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
197
|
+
"entropy": 3.5
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"id": "upstash-redis-rest-token.1",
|
|
201
|
+
"description": "Upstash Redis REST token, which may grant read-only or full access to an Upstash database.",
|
|
202
|
+
"regex": "(?i:(?:upstash)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3})(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}((?:[A-Za-z0-9]{32,48}|AYNgAS[A-Za-z0-9+/_-]{26,90}={0,2}))(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
203
|
+
"keywords": [
|
|
204
|
+
"upstash"
|
|
205
|
+
],
|
|
206
|
+
"confidence": "high",
|
|
207
|
+
"filter": "entropy(finding[\"secret\"]) < 3.5\n",
|
|
208
|
+
"entropy": 3.5
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"id": "val-town-api-token.1",
|
|
212
|
+
"description": "Val Town API token.",
|
|
213
|
+
"regex": "\\b(vtwn_[A-Za-z0-9_-]{20,80})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
214
|
+
"keywords": [
|
|
215
|
+
"vtwn_"
|
|
216
|
+
],
|
|
217
|
+
"confidence": "high",
|
|
218
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5\n|| !filter.matchesAny(finding[\"secret\"], [\"^(?:[^0-9]*[0-9]){2}\"])\n",
|
|
219
|
+
"entropy": 3.5,
|
|
220
|
+
"require": [
|
|
221
|
+
"^(?:[^0-9]*[0-9]){2}"
|
|
222
|
+
]
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"id": "vercel-ai-gateway-key",
|
|
226
|
+
"description": "Detected a Vercel AI Gateway API Key (vck_), which may expose AI model routing and gateway access to unauthorized parties.",
|
|
227
|
+
"regex": "(?i)\\b(vck_[A-Za-z0-9_-]{56})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
228
|
+
"keywords": [
|
|
229
|
+
"vck_"
|
|
230
|
+
],
|
|
231
|
+
"confidence": "high",
|
|
232
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
233
|
+
"entropy": 3.5
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"id": "vercel-api-token",
|
|
237
|
+
"description": "Detected a Vercel API Token, which may expose deployment and serverless infrastructure to unauthorized access.",
|
|
238
|
+
"regex": "(?i)(?:vercel)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([A-Z0-9]{24})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
239
|
+
"keywords": [
|
|
240
|
+
"vercel"
|
|
241
|
+
],
|
|
242
|
+
"confidence": "high",
|
|
243
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
244
|
+
"entropy": 3.5
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"id": "vercel-app-access-token",
|
|
248
|
+
"description": "Detected a Vercel App Access Token (vca_), which may allow Sign in with Vercel apps to access user resources.",
|
|
249
|
+
"regex": "(?i)\\b(vca_[A-Za-z0-9_-]{56})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
250
|
+
"keywords": [
|
|
251
|
+
"vca_"
|
|
252
|
+
],
|
|
253
|
+
"confidence": "high",
|
|
254
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
255
|
+
"entropy": 3.5
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"id": "vercel-app-refresh-token",
|
|
259
|
+
"description": "Detected a Vercel App Refresh Token (vcr_), which may allow persistent unauthorized access through token refresh flows.",
|
|
260
|
+
"regex": "(?i)\\b(vcr_[A-Za-z0-9_-]{56})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
261
|
+
"keywords": [
|
|
262
|
+
"vcr_"
|
|
263
|
+
],
|
|
264
|
+
"confidence": "high",
|
|
265
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
266
|
+
"entropy": 3.5
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"id": "vercel-integration-token",
|
|
270
|
+
"description": "Detected a Vercel Integration Token (vci_), which may allow third-party service integrations to act on behalf of users.",
|
|
271
|
+
"regex": "(?i)\\b(vci_[A-Za-z0-9_-]{56})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
272
|
+
"keywords": [
|
|
273
|
+
"vci_"
|
|
274
|
+
],
|
|
275
|
+
"confidence": "high",
|
|
276
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
277
|
+
"entropy": 3.5
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"id": "vercel-personal-access-token",
|
|
281
|
+
"description": "Detected a Vercel Personal Access Token (vcp_), which may expose full account and deployment management capabilities.",
|
|
282
|
+
"regex": "(?i)\\b(vcp_[A-Za-z0-9_-]{56})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
283
|
+
"keywords": [
|
|
284
|
+
"vcp_"
|
|
285
|
+
],
|
|
286
|
+
"confidence": "high",
|
|
287
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
288
|
+
"entropy": 3.5
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"id": "virustotal-api-key.1",
|
|
292
|
+
"description": "VirusTotal API key, which may expose private submissions, intelligence, or account API access.",
|
|
293
|
+
"regex": "(?i)(?:virustotal)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([a-f0-9]{64})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
294
|
+
"keywords": [
|
|
295
|
+
"virustotal"
|
|
296
|
+
],
|
|
297
|
+
"confidence": "high",
|
|
298
|
+
"filter": "entropy(finding[\"secret\"]) < 3.5\n",
|
|
299
|
+
"entropy": 3.5
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"id": "voyageai-api-key",
|
|
303
|
+
"description": "Detected a Voyage AI API key, which may expose embedding and retrieval model access to unauthorized parties.",
|
|
304
|
+
"regex": "(?i:(?:voyage)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3})(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}((?:pa|al)-[A-Za-z0-9_-]{43})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
305
|
+
"keywords": [
|
|
306
|
+
"voyage"
|
|
307
|
+
],
|
|
308
|
+
"confidence": "medium",
|
|
309
|
+
"filter": "entropy(finding[\"secret\"]) < 4.0\n",
|
|
310
|
+
"entropy": 4.0
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"id": "vultr-api-key.1",
|
|
314
|
+
"description": "Vultr API key, which may allow management of cloud account resources.",
|
|
315
|
+
"regex": "(?i)(?:vultr)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([a-f0-9]{36})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
316
|
+
"keywords": [
|
|
317
|
+
"vultr"
|
|
318
|
+
],
|
|
319
|
+
"confidence": "medium",
|
|
320
|
+
"filter": "entropy(finding[\"secret\"]) < 3.4\n",
|
|
321
|
+
"entropy": 3.4
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
"id": "wakatime-api-key.1",
|
|
325
|
+
"description": "WakaTime API key version 1 (UUID format).",
|
|
326
|
+
"regex": "(?i:(?:waka[_. -]?time(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3})(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
327
|
+
"keywords": [
|
|
328
|
+
"wakatime",
|
|
329
|
+
"waka_time",
|
|
330
|
+
"waka-time",
|
|
331
|
+
"waka time",
|
|
332
|
+
"waka.time"
|
|
333
|
+
],
|
|
334
|
+
"confidence": "high",
|
|
335
|
+
"filter": "entropy(finding[\"secret\"]) < 3.0\n",
|
|
336
|
+
"entropy": 3.0
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"id": "wakatime-api-key.2",
|
|
340
|
+
"description": "WakaTime API key version 2 (waka_ format).",
|
|
341
|
+
"regex": "(?i)\\b(waka_[a-z0-9]{36,64})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
342
|
+
"keywords": [
|
|
343
|
+
"waka_"
|
|
344
|
+
],
|
|
345
|
+
"confidence": "high",
|
|
346
|
+
"filter": "entropy(finding[\"secret\"]) < 3.0\n",
|
|
347
|
+
"entropy": 3.0
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"id": "weatherstack-api-key.1",
|
|
351
|
+
"description": "Weatherstack API key.",
|
|
352
|
+
"regex": "(?i:(?:weatherstack(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3})(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([0-9a-z]{32})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
353
|
+
"keywords": [
|
|
354
|
+
"weatherstack"
|
|
355
|
+
],
|
|
356
|
+
"confidence": "medium",
|
|
357
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.3 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
358
|
+
"entropy": 3.3
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"id": "weights-and-biases-api-key",
|
|
362
|
+
"description": "Detected a Weights & Biases API Key, which may expose ML experiment tracking and model registry access to unauthorized parties.",
|
|
363
|
+
"regex": "(?i)(?:wandb|weightsandbiases)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([a-f0-9]{40})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
364
|
+
"keywords": [
|
|
365
|
+
"wandb",
|
|
366
|
+
"weightsandbiases"
|
|
367
|
+
],
|
|
368
|
+
"confidence": "medium",
|
|
369
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
370
|
+
"entropy": 3.5
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"id": "weights-and-biases-api-key-v1",
|
|
374
|
+
"description": "Detected a Weights & Biases v1 API Key (wandb_v1_), which may expose ML experiment tracking and artifact storage to unauthorized access.",
|
|
375
|
+
"regex": "(?i)\\b(wandb_v1_[A-Za-z0-9_]{77})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
376
|
+
"keywords": [
|
|
377
|
+
"wandb_v1_"
|
|
378
|
+
],
|
|
379
|
+
"confidence": "high",
|
|
380
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5 || filter.tokenRatio(finding[\"secret\"]) >= 2.5\n",
|
|
381
|
+
"entropy": 3.5
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
"id": "wiz-client-secret.1",
|
|
385
|
+
"description": "Wiz OAuth client secret, which may allow access to the Wiz API when paired with its client ID.",
|
|
386
|
+
"regex": "(?i:(?:wiz)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3})(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([A-Za-z0-9]{64})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
387
|
+
"keywords": [
|
|
388
|
+
"wiz"
|
|
389
|
+
],
|
|
390
|
+
"confidence": "high",
|
|
391
|
+
"filter": "entropy(finding[\"secret\"]) < 4.0\n",
|
|
392
|
+
"entropy": 4.0
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"id": "woocommerce-consumer-secret.1",
|
|
396
|
+
"description": "WooCommerce REST API consumer secret, which may allow read or write access to a store with the associated consumer key.",
|
|
397
|
+
"regex": "(?i)(?:woo)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}(cs_[a-f0-9]{40})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
398
|
+
"keywords": [
|
|
399
|
+
"wooc",
|
|
400
|
+
"woo-",
|
|
401
|
+
"woo_",
|
|
402
|
+
"cs_"
|
|
403
|
+
],
|
|
404
|
+
"confidence": "high",
|
|
405
|
+
"filter": "entropy(finding[\"secret\"]) < 3.5\n",
|
|
406
|
+
"entropy": 3.5
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
"id": "workato-developer-api-token.1",
|
|
410
|
+
"description": "Workato Developer API token.",
|
|
411
|
+
"regex": "\\b(wrka(?:[a-z]{2})?-eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{16,}\\.[A-Za-z0-9_-]{64,})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
412
|
+
"keywords": [
|
|
413
|
+
"wrka"
|
|
414
|
+
],
|
|
415
|
+
"confidence": "high",
|
|
416
|
+
"filter": "entropy(finding[\"secret\"]) < 4.0\n",
|
|
417
|
+
"entropy": 4.0
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
"id": "workos-production-api-key.1",
|
|
421
|
+
"description": "WorkOS production API key.",
|
|
422
|
+
"regex": "(?i:(?:workos(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3})(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}(sk_live_a2V5Xz[A-Za-z0-9+/]{69}={0,2})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
423
|
+
"keywords": [
|
|
424
|
+
"workos"
|
|
425
|
+
],
|
|
426
|
+
"confidence": "high",
|
|
427
|
+
"filter": "filter.entropy(finding[\"secret\"]) < 3.5\n|| filter.matchesAny(finding[\"secret\"], [\"(?i)example\"])\n",
|
|
428
|
+
"entropy": 3.5,
|
|
429
|
+
"reject": [
|
|
430
|
+
"(?i)example"
|
|
431
|
+
]
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"id": "xai-api-key",
|
|
435
|
+
"description": "Detected an xAI (Grok) API Key, which may expose Grok AI model access to unauthorized parties.",
|
|
436
|
+
"regex": "(?i)\\b(xai-[A-Za-z0-9_-]{70,120})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
437
|
+
"keywords": [
|
|
438
|
+
"xai-"
|
|
439
|
+
],
|
|
440
|
+
"confidence": "high",
|
|
441
|
+
"filter": "entropy(finding[\"secret\"]) <= 3.5\n",
|
|
442
|
+
"entropy": 3.5,
|
|
443
|
+
"entropyInclusive": true
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"id": "xendit-production-api-key.1",
|
|
447
|
+
"description": "Xendit production API key, which may allow access to payment and balance APIs.",
|
|
448
|
+
"regex": "\\b(xnd_production_[A-Za-z0-9]{56,72})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
449
|
+
"keywords": [
|
|
450
|
+
"xnd_production_"
|
|
451
|
+
],
|
|
452
|
+
"confidence": "high",
|
|
453
|
+
"filter": "entropy(finding[\"secret\"]) < 3.0\n",
|
|
454
|
+
"entropy": 3.0
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
"id": "zai-api-key",
|
|
458
|
+
"description": "Detected a Z.ai API key, which may expose GLM model access and usage to unauthorized parties.",
|
|
459
|
+
"regex": "(?i)(?:zai|z_ai|z\\.ai|glm|zlm)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([a-f0-9]{32}\\.[a-z0-9]{16})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
460
|
+
"keywords": [
|
|
461
|
+
"zai",
|
|
462
|
+
"z_ai",
|
|
463
|
+
"z.ai",
|
|
464
|
+
"glm",
|
|
465
|
+
"zlm"
|
|
466
|
+
],
|
|
467
|
+
"confidence": "medium",
|
|
468
|
+
"filter": "entropy(finding[\"secret\"]) <= 3.5\n",
|
|
469
|
+
"entropy": 3.5,
|
|
470
|
+
"entropyInclusive": true
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"id": "zoho-client-secret.1",
|
|
474
|
+
"description": "Zoho OAuth client secret, which may allow OAuth client authentication when paired with the associated client ID.",
|
|
475
|
+
"regex": "(?i)(?:zoho)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}([a-f0-9]{42})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
476
|
+
"keywords": [
|
|
477
|
+
"zoho"
|
|
478
|
+
],
|
|
479
|
+
"confidence": "high",
|
|
480
|
+
"filter": "entropy(finding[\"secret\"]) < 3.5\n",
|
|
481
|
+
"entropy": 3.5
|
|
482
|
+
}
|
|
483
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "zoho-oauth-token.1",
|
|
4
|
+
"description": "Zoho OAuth access or refresh token, which may allow access to Zoho APIs or minting of new access tokens.",
|
|
5
|
+
"regex": "(?i)(?:zoho)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}(1000\\.[a-f0-9]{32}\\.[a-f0-9]{32})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"zoho"
|
|
8
|
+
],
|
|
9
|
+
"confidence": "high",
|
|
10
|
+
"filter": "entropy(finding[\"secret\"]) < 3.5\n",
|
|
11
|
+
"entropy": 3.5
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "zoho-zapi-key.1",
|
|
15
|
+
"description": "Zoho ZAPI key, which may authorize CRM functions, extensions, webhooks, or other Zoho APIs.",
|
|
16
|
+
"regex": "(?i)(?:zoho)(?:[ \\t\\w.-]{0,20})[\\s'\"]{0,3}(?:=|>|:{1,3}=|\\|\\||:|=>|\\?=|,)[\\x60'\"\\s=]{0,5}((?:1001\\.[a-f0-9]{32}\\.[a-f0-9]{32}(?:-d)?|1003\\.[a-f0-9]{32,64}))(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"zoho"
|
|
19
|
+
],
|
|
20
|
+
"confidence": "high",
|
|
21
|
+
"filter": "entropy(finding[\"secret\"]) < 3.5\n",
|
|
22
|
+
"entropy": 3.5
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "zuplo-consumer-api-key.1",
|
|
26
|
+
"description": "Zuplo consumer API key.",
|
|
27
|
+
"regex": "\\b(zpka_[a-z0-9]{32}_[0-9a-f]{8})(?:\\\\?['\"\\x60]|[\\s;]|\\\\[nr]|$)",
|
|
28
|
+
"keywords": [
|
|
29
|
+
"zpka_"
|
|
30
|
+
],
|
|
31
|
+
"confidence": "high",
|
|
32
|
+
"filter": "entropy(finding[\"secret\"]) < 3.3\n",
|
|
33
|
+
"entropy": 3.3
|
|
34
|
+
}
|
|
35
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "https://docs.aws.amazon.com/comprehend/latest/dg/how-pii.html",
|
|
3
|
-
"sha256": "
|
|
3
|
+
"sha256": "6ed623108ec7f4d4280d7d80fb437941a1210a90d72c83359dafae8ebb53b787",
|
|
4
4
|
"names": [
|
|
5
5
|
"ADDRESS",
|
|
6
6
|
"AGE",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "https://learn.microsoft.com/en-us/azure/ai-services/language-service/personally-identifiable-information/concepts/entity-categories",
|
|
3
|
-
"sha256": "
|
|
3
|
+
"sha256": "0a07d66b5779f6dd9391937948b05e32a6d3fcdd2a1e870384ffae10cb837c7b",
|
|
4
4
|
"names": [
|
|
5
5
|
"ABARoutingNumber",
|
|
6
6
|
"ARNationalIdentityNumber",
|
|
@@ -150,11 +150,13 @@
|
|
|
150
150
|
"RUPassportNumberInternational",
|
|
151
151
|
"SANationalID",
|
|
152
152
|
"SENationalID",
|
|
153
|
+
"SEPassportNumber",
|
|
153
154
|
"SETaxIdentificationNumber",
|
|
154
155
|
"SGNationalRegistrationIdentityCardNumber",
|
|
155
156
|
"SITaxIdentificationNumber",
|
|
156
157
|
"SIUniqueMasterCitizenNumber",
|
|
157
158
|
"SKPersonalNumber",
|
|
159
|
+
"SQLServerConnectionString",
|
|
158
160
|
"SWIFTCode",
|
|
159
161
|
"SortCode",
|
|
160
162
|
"State",
|
|
@@ -174,9 +176,11 @@
|
|
|
174
176
|
"USBankAccountNumber",
|
|
175
177
|
"USDriversLicenseNumber",
|
|
176
178
|
"USIndividualTaxpayerIdentification",
|
|
179
|
+
"USMedicareBeneficiaryId",
|
|
177
180
|
"USSocialSecurityNumber",
|
|
178
181
|
"USUKPassportNumber",
|
|
179
182
|
"VIN",
|
|
180
|
-
"ZAIdentificationNumber"
|
|
183
|
+
"ZAIdentificationNumber",
|
|
184
|
+
"ZipCode"
|
|
181
185
|
]
|
|
182
186
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "https://docs.cloud.google.com/sensitive-data-protection/docs/infotypes-reference",
|
|
3
|
-
"sha256": "
|
|
3
|
+
"sha256": "e12d6c62e670a580545f3e342c347ba6f102d485bdc4fee0b7e220bcc7822b92",
|
|
4
4
|
"names": [
|
|
5
5
|
"ADVERTISING_ID",
|
|
6
6
|
"AGE",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"DRIVERS_LICENSE_NUMBER",
|
|
54
54
|
"EMAIL_ADDRESS",
|
|
55
55
|
"EMPLOYMENT_STATUS",
|
|
56
|
+
"ENCODED_BLOCK",
|
|
56
57
|
"ENCRYPTION_KEY",
|
|
57
58
|
"ETHNIC_GROUP",
|
|
58
59
|
"FDA_CODE",
|
package/src/vocabulary.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { failure, collectMatches } from './detection.js';
|
|
1
|
+
import { failure, collectMatches, escapePattern } from './detection.js';
|
|
2
2
|
import { wordPattern } from './personal-variants.js';
|
|
3
3
|
import { fieldSuffixes, normalizeFieldName } from './document-fields.js';
|
|
4
4
|
|
|
@@ -50,6 +50,7 @@ export const defaultVocabulary = Object.freeze(
|
|
|
50
50
|
'fullname',
|
|
51
51
|
'originalfilename',
|
|
52
52
|
],
|
|
53
|
+
personalAttributes: [],
|
|
53
54
|
}).map(([key, values]) => [key, Object.freeze(values)])
|
|
54
55
|
)
|
|
55
56
|
);
|
|
@@ -111,6 +112,30 @@ function normalizedList(input, defaults) {
|
|
|
111
112
|
),
|
|
112
113
|
];
|
|
113
114
|
}
|
|
115
|
+
// Caller stems for the strict special-category rule: each word matches at a
|
|
116
|
+
// word start and takes at most eight more letters of ending, like the built-in
|
|
117
|
+
// stems, so `узбеч` covers `узбечка` and `узбечкой`.
|
|
118
|
+
function attributePattern(values) {
|
|
119
|
+
if (!values.length) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const stems = values
|
|
123
|
+
.map((value) =>
|
|
124
|
+
value
|
|
125
|
+
.split(/\s+/u)
|
|
126
|
+
.map(
|
|
127
|
+
(word) =>
|
|
128
|
+
`${escapePattern(word).replace(/[её]/gu, '[её]')}[\\p{L}\\p{M}]{0,8}`
|
|
129
|
+
)
|
|
130
|
+
.join('[ \\t]+')
|
|
131
|
+
)
|
|
132
|
+
.sort((a, b) => b.length - a.length)
|
|
133
|
+
.join('|');
|
|
134
|
+
return new RegExp(
|
|
135
|
+
`(?<![\\p{L}\\p{N}_])(?:${stems})(?![\\p{L}\\p{N}_])`,
|
|
136
|
+
'giu'
|
|
137
|
+
);
|
|
138
|
+
}
|
|
114
139
|
export function compiledVocabulary(vocabulary) {
|
|
115
140
|
if (vocabulary === undefined) {
|
|
116
141
|
return undefined;
|
|
@@ -159,6 +184,7 @@ export function compiledVocabulary(vocabulary) {
|
|
|
159
184
|
'giu'
|
|
160
185
|
);
|
|
161
186
|
result.fields = new Set(lists.personalFields.map(normalizeFieldName));
|
|
187
|
+
result.attributes = attributePattern(lists.personalAttributes);
|
|
162
188
|
if (cache.size >= 64) {
|
|
163
189
|
cache.clear();
|
|
164
190
|
}
|