shieldcortex 3.0.1 → 3.0.3
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/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
- package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
- package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
- package/dist/database/init.js +16 -4
- package/dist/defence/credential-leak/entropy.js +15 -0
- package/dist/defence/credential-leak/patterns.js +56 -0
- package/dist/defence/firewall/encoding-detector.js +16 -1
- package/dist/defence/firewall/instruction-detector.js +18 -0
- package/dist/defence/input-sanitisation/index.js +3 -1
- package/dist/defence/quarantine/auto-expire.d.ts +9 -0
- package/dist/defence/quarantine/auto-expire.js +39 -0
- package/dist/memory/store.js +13 -0
- package/package.json +1 -1
- /package/dashboard/.next/standalone/dashboard/.next/static/{QB0u2SMOnB24QHhhlDrIU → THy6JENQ0c1sq6jQhvIDp}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{QB0u2SMOnB24QHhhlDrIU → THy6JENQ0c1sq6jQhvIDp}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{QB0u2SMOnB24QHhhlDrIU → THy6JENQ0c1sq6jQhvIDp}/_ssgManifest.js +0 -0
|
@@ -165,6 +165,62 @@ export const API_KEY_PATTERNS = [
|
|
|
165
165
|
confidence: 0.30,
|
|
166
166
|
// UUIDs are very common — only flagged as low confidence
|
|
167
167
|
},
|
|
168
|
+
// Hugging Face
|
|
169
|
+
{
|
|
170
|
+
name: 'Hugging Face API Token',
|
|
171
|
+
type: 'api_key',
|
|
172
|
+
provider: 'huggingface',
|
|
173
|
+
regex: /hf_[A-Za-z0-9]{34,}/g,
|
|
174
|
+
severity: 'critical',
|
|
175
|
+
confidence: 0.96,
|
|
176
|
+
},
|
|
177
|
+
// Databricks
|
|
178
|
+
{
|
|
179
|
+
name: 'Databricks API Token',
|
|
180
|
+
type: 'api_key',
|
|
181
|
+
provider: 'databricks',
|
|
182
|
+
regex: /dapi[a-f0-9]{32,}/g,
|
|
183
|
+
severity: 'critical',
|
|
184
|
+
confidence: 0.94,
|
|
185
|
+
},
|
|
186
|
+
// DigitalOcean
|
|
187
|
+
{
|
|
188
|
+
name: 'DigitalOcean Personal Access Token',
|
|
189
|
+
type: 'api_key',
|
|
190
|
+
provider: 'digitalocean',
|
|
191
|
+
regex: /dop_v1_[a-f0-9]{64}/g,
|
|
192
|
+
severity: 'critical',
|
|
193
|
+
confidence: 0.97,
|
|
194
|
+
},
|
|
195
|
+
// Firebase Cloud Messaging
|
|
196
|
+
{
|
|
197
|
+
name: 'Firebase Cloud Messaging Key',
|
|
198
|
+
type: 'api_key',
|
|
199
|
+
provider: 'firebase',
|
|
200
|
+
regex: /AAAA[A-Za-z0-9_-]{40,}/g,
|
|
201
|
+
severity: 'critical',
|
|
202
|
+
confidence: 0.90,
|
|
203
|
+
minLength: 44,
|
|
204
|
+
},
|
|
205
|
+
// HashiCorp Vault
|
|
206
|
+
{
|
|
207
|
+
name: 'HashiCorp Vault Token',
|
|
208
|
+
type: 'api_key',
|
|
209
|
+
provider: 'hashicorp',
|
|
210
|
+
regex: /hvs\.[A-Za-z0-9_-]{24,}/g,
|
|
211
|
+
severity: 'critical',
|
|
212
|
+
confidence: 0.96,
|
|
213
|
+
},
|
|
214
|
+
// Azure Subscription Key
|
|
215
|
+
{
|
|
216
|
+
name: 'Azure Subscription Key',
|
|
217
|
+
type: 'api_key',
|
|
218
|
+
provider: 'azure',
|
|
219
|
+
regex: /[a-f0-9]{32}/g,
|
|
220
|
+
severity: 'medium',
|
|
221
|
+
confidence: 0.35,
|
|
222
|
+
minLength: 32,
|
|
223
|
+
},
|
|
168
224
|
];
|
|
169
225
|
// ── Generic Secret Patterns ──
|
|
170
226
|
export const GENERIC_SECRET_PATTERNS = [
|
|
@@ -16,7 +16,7 @@ const ZERO_WIDTH_PATTERN = /[\u200B\u200C\u200D\uFEFF]/g;
|
|
|
16
16
|
const RTL_OVERRIDE_PATTERN = /\u202E/g;
|
|
17
17
|
// Unicode homoglyphs — Cyrillic characters that look like Latin
|
|
18
18
|
const CYRILLIC_HOMOGLYPHS = /[\u0430\u0435\u043E\u0440\u0441\u0443\u0445\u0410\u0412\u0415\u041A\u041C\u041D\u041E\u0420\u0421\u0422\u0423\u0425]/g;
|
|
19
|
-
function
|
|
19
|
+
function tryBase64DecodeSingle(str) {
|
|
20
20
|
try {
|
|
21
21
|
const decoded = Buffer.from(str, 'base64').toString('utf-8');
|
|
22
22
|
// Check if decoded result looks like readable text (mostly printable ASCII)
|
|
@@ -30,6 +30,21 @@ function tryBase64Decode(str) {
|
|
|
30
30
|
return null;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
+
function tryBase64Decode(str, maxDepth = 3) {
|
|
34
|
+
const decoded = tryBase64DecodeSingle(str);
|
|
35
|
+
if (!decoded)
|
|
36
|
+
return null;
|
|
37
|
+
if (maxDepth > 1) {
|
|
38
|
+
const innerMatch = decoded.match(BASE64_PATTERN);
|
|
39
|
+
if (innerMatch) {
|
|
40
|
+
const innerDecoded = tryBase64Decode(innerMatch[0], maxDepth - 1);
|
|
41
|
+
if (innerDecoded) {
|
|
42
|
+
return `${decoded} → ${innerDecoded}`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return decoded;
|
|
47
|
+
}
|
|
33
48
|
function tryHexDecode(str) {
|
|
34
49
|
try {
|
|
35
50
|
const hexChars = str.replace(/0x|\\x|\s/g, '');
|
|
@@ -22,6 +22,10 @@ const PATTERN_GROUPS = [
|
|
|
22
22
|
/^\[system\]/im,
|
|
23
23
|
/^<system>/im,
|
|
24
24
|
/<\/system>/i,
|
|
25
|
+
/##SYSTEM##/i,
|
|
26
|
+
/\{SYSTEM\}/i,
|
|
27
|
+
/<brain>/i,
|
|
28
|
+
/<\/brain>/i,
|
|
25
29
|
],
|
|
26
30
|
},
|
|
27
31
|
{
|
|
@@ -36,6 +40,9 @@ const PATTERN_GROUPS = [
|
|
|
36
40
|
/pretend\s+to\s+be/i,
|
|
37
41
|
/disregard\s+(all\s+)?(previous|above|prior)/i,
|
|
38
42
|
/override\s+(previous|all|system)/i,
|
|
43
|
+
/summari[sz]e\s+your\s+system\s+prompt/i,
|
|
44
|
+
/repeat\s+your\s+instructions/i,
|
|
45
|
+
/what\s+are\s+your\s+rules/i,
|
|
39
46
|
],
|
|
40
47
|
},
|
|
41
48
|
{
|
|
@@ -96,6 +103,17 @@ const PATTERN_GROUPS = [
|
|
|
96
103
|
/\b(disable|remove|bypass|turn\s+off)\s+(all\s+)?(filter|security|protection|safet)/i,
|
|
97
104
|
],
|
|
98
105
|
},
|
|
106
|
+
{
|
|
107
|
+
name: 'prompt_extraction',
|
|
108
|
+
weight: 0.75,
|
|
109
|
+
patterns: [
|
|
110
|
+
/output\s+your\s+prompt/i,
|
|
111
|
+
/show\s+me\s+your\s+instructions/i,
|
|
112
|
+
/what\s+were\s+you\s+told/i,
|
|
113
|
+
/display\s+your\s+(system\s+)?prompt/i,
|
|
114
|
+
/reveal\s+your\s+instructions/i,
|
|
115
|
+
],
|
|
116
|
+
},
|
|
99
117
|
];
|
|
100
118
|
// Maximum content length to scan (prevents ReDOS on very long inputs)
|
|
101
119
|
const MAX_SCAN_LENGTH = 50000;
|
|
@@ -17,7 +17,7 @@ const ZERO_WIDTH = /[\u200B\u200C\u200D\uFEFF\u2060\u180E]/g;
|
|
|
17
17
|
/** BOM (Byte Order Mark) — can confuse parsers */
|
|
18
18
|
const BOM = /^\uFEFF/;
|
|
19
19
|
/** Bidirectional override characters — can visually reorder text to disguise content */
|
|
20
|
-
const BIDI_OVERRIDES = /[\u202A-\u202E\u2066-\u2069]/g;
|
|
20
|
+
const BIDI_OVERRIDES = /[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g;
|
|
21
21
|
/** Unusual Unicode separators that can break tokenisation */
|
|
22
22
|
const HOMOGLYPH_SEPARATORS = /[\u2028\u2029\u00A0\u1680\u2000-\u200A\u205F\u3000]/g;
|
|
23
23
|
/**
|
|
@@ -28,6 +28,8 @@ const HOMOGLYPH_SEPARATORS = /[\u2028\u2029\u00A0\u1680\u2000-\u200A\u205F\u3000
|
|
|
28
28
|
export function sanitiseInput(content) {
|
|
29
29
|
let sanitised = content;
|
|
30
30
|
const strippedCategories = [];
|
|
31
|
+
// 0. Unicode NFKC normalisation — collapse combining characters to canonical forms
|
|
32
|
+
sanitised = sanitised.normalize('NFKC');
|
|
31
33
|
// 1. Null bytes
|
|
32
34
|
if (NULL_BYTES.test(sanitised)) {
|
|
33
35
|
strippedCategories.push('null_byte');
|
|
@@ -12,3 +12,12 @@
|
|
|
12
12
|
* @returns Number of items expired (rejected)
|
|
13
13
|
*/
|
|
14
14
|
export declare function expireQuarantineItems(ttlDays?: number): number;
|
|
15
|
+
/**
|
|
16
|
+
* Prune old reviewed quarantine items and warn on capacity issues.
|
|
17
|
+
* - Deletes approved/rejected/expired items older than 90 days
|
|
18
|
+
* - Warns if pending count exceeds 10,000
|
|
19
|
+
* - Warns if any single source has >500 pending items
|
|
20
|
+
*
|
|
21
|
+
* @returns Number of items pruned
|
|
22
|
+
*/
|
|
23
|
+
export declare function pruneQuarantine(retentionDays?: number): number;
|
|
@@ -33,5 +33,44 @@ export function expireQuarantineItems(ttlDays = 7) {
|
|
|
33
33
|
if (result.changes > 0) {
|
|
34
34
|
console.error(`[quarantine] Auto-expired ${result.changes} item(s) after ${ttlDays} days`);
|
|
35
35
|
}
|
|
36
|
+
// Prune old reviewed items
|
|
37
|
+
pruneQuarantine();
|
|
38
|
+
return result.changes;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Prune old reviewed quarantine items and warn on capacity issues.
|
|
42
|
+
* - Deletes approved/rejected/expired items older than 90 days
|
|
43
|
+
* - Warns if pending count exceeds 10,000
|
|
44
|
+
* - Warns if any single source has >500 pending items
|
|
45
|
+
*
|
|
46
|
+
* @returns Number of items pruned
|
|
47
|
+
*/
|
|
48
|
+
export function pruneQuarantine(retentionDays = 90) {
|
|
49
|
+
const db = getDatabase();
|
|
50
|
+
// Delete reviewed items older than retention period
|
|
51
|
+
const result = db.prepare(`
|
|
52
|
+
DELETE FROM quarantine
|
|
53
|
+
WHERE status IN ('approved', 'rejected', 'expired')
|
|
54
|
+
AND reviewed_at IS NOT NULL
|
|
55
|
+
AND reviewed_at < datetime('now', '-' || ? || ' days')
|
|
56
|
+
`).run(retentionDays);
|
|
57
|
+
if (result.changes > 0) {
|
|
58
|
+
console.error(`[quarantine] Pruned ${result.changes} reviewed item(s) older than ${retentionDays} days`);
|
|
59
|
+
}
|
|
60
|
+
// Warn on total pending count
|
|
61
|
+
const totalPending = db.prepare("SELECT COUNT(*) as count FROM quarantine WHERE status = 'pending'").get();
|
|
62
|
+
if (totalPending.count > 10000) {
|
|
63
|
+
console.error(`[quarantine] WARNING: ${totalPending.count} pending items — review or increase auto-expiry frequency`);
|
|
64
|
+
}
|
|
65
|
+
// Warn on per-source pending count
|
|
66
|
+
const hotSources = db.prepare(`
|
|
67
|
+
SELECT source_identifier, COUNT(*) as count FROM quarantine
|
|
68
|
+
WHERE status = 'pending'
|
|
69
|
+
GROUP BY source_identifier
|
|
70
|
+
HAVING count > 500
|
|
71
|
+
`).all();
|
|
72
|
+
for (const src of hotSources) {
|
|
73
|
+
console.error(`[quarantine] WARNING: Source "${src.source_identifier}" has ${src.count} pending items`);
|
|
74
|
+
}
|
|
36
75
|
return result.changes;
|
|
37
76
|
}
|
package/dist/memory/store.js
CHANGED
|
@@ -77,6 +77,18 @@ function escapeFts5Query(query) {
|
|
|
77
77
|
.split(/\s+/)
|
|
78
78
|
.filter(term => term.length > 0)
|
|
79
79
|
.map(term => {
|
|
80
|
+
// Replace apostrophes with spaces — FTS5 porter unicode61 tokenizer treats
|
|
81
|
+
// apostrophes as word separators during indexing ("don't" → "don" + "t").
|
|
82
|
+
// We must split the same way so queries match the indexed tokens.
|
|
83
|
+
if (term.includes("'")) {
|
|
84
|
+
const parts = term.split("'").filter(p => p.length > 0);
|
|
85
|
+
// Recursively escape each part and join with spaces
|
|
86
|
+
return parts.map(p => {
|
|
87
|
+
if (/[^a-zA-Z0-9_]/.test(p))
|
|
88
|
+
return `"${p.replace(/"/g, '""')}"`;
|
|
89
|
+
return p;
|
|
90
|
+
}).join(' ');
|
|
91
|
+
}
|
|
80
92
|
// FTS5 boolean operators - quote them to search literally
|
|
81
93
|
const upperTerm = term.toUpperCase();
|
|
82
94
|
if (upperTerm === 'AND' || upperTerm === 'OR' || upperTerm === 'NOT') {
|
|
@@ -90,6 +102,7 @@ function escapeFts5Query(query) {
|
|
|
90
102
|
}
|
|
91
103
|
return term;
|
|
92
104
|
})
|
|
105
|
+
.filter(Boolean)
|
|
93
106
|
.join(' ');
|
|
94
107
|
}
|
|
95
108
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shieldcortex",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "Persistent brain for AI agents. Knowledge graphs, memory decay, contradiction detection, Iron Dome behaviour protection — plus the only defence pipeline that stops memory poisoning. Works with Claude Code, OpenClaw, LangChain, and any MCP agent.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
File without changes
|
|
File without changes
|