shrike-guard 1.3.3 → 4.0.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/README.md +16 -16
- package/dist/anthropic/index.d.mts +1 -1
- package/dist/anthropic/index.d.ts +1 -1
- package/dist/anthropic/index.js +107 -29
- package/dist/anthropic/index.js.map +1 -1
- package/dist/anthropic/index.mjs +107 -29
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/api/index.d.mts +4 -98
- package/dist/api/index.d.ts +4 -98
- package/dist/api/index.js +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/index.mjs +1 -1
- package/dist/api/index.mjs.map +1 -1
- package/dist/auth-DotJtJHE.d.mts +97 -0
- package/dist/auth-DotJtJHE.d.ts +97 -0
- package/dist/gemini/index.d.mts +1 -1
- package/dist/gemini/index.d.ts +1 -1
- package/dist/gemini/index.js +110 -32
- package/dist/gemini/index.js.map +1 -1
- package/dist/gemini/index.mjs +110 -32
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.d.mts +532 -6
- package/dist/index.d.ts +532 -6
- package/dist/index.js +946 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +930 -33
- package/dist/index.mjs.map +1 -1
- package/dist/openai/index.d.mts +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/openai/index.js +109 -31
- package/dist/openai/index.js.map +1 -1
- package/dist/openai/index.mjs +109 -31
- package/dist/openai/index.mjs.map +1 -1
- package/dist/{scanner-CkCXFY3H.d.mts → scanner-RWQR_jcB.d.mts} +142 -2
- package/dist/{scanner-CkCXFY3H.d.ts → scanner-RWQR_jcB.d.ts} +142 -2
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://nodejs.org/)
|
|
5
5
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
6
6
|
|
|
7
|
-
**Shrike Guard** is a TypeScript SDK for the [Shrike](https://shrikesecurity.com) platform — AI governance for every AI interaction. It wraps OpenAI, Anthropic (Claude), and Google Gemini clients to automatically evaluate all prompts against policy before they reach the LLM. Whether you're governing a customer-facing chatbot, securing developer AI tools, or managing autonomous agent actions — the same
|
|
7
|
+
**Shrike Guard** is a TypeScript SDK for the [Shrike](https://shrikesecurity.com) platform — AI governance for every AI interaction. It wraps OpenAI, Anthropic (Claude), and Google Gemini clients to automatically evaluate all prompts against policy before they reach the LLM. Whether you're governing a customer-facing chatbot, securing developer AI tools, or managing autonomous agent actions — the same 9-layer cognitive pipeline evaluates every interaction.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
- Jailbreak attempts
|
|
16
16
|
- SQL injection
|
|
17
17
|
- Path traversal
|
|
18
|
-
- **Fail-safe modes**:
|
|
18
|
+
- **Fail-safe modes**: Defaults to fail-closed (Zero Trust posture); opt into fail-open explicitly when availability outranks enforcement
|
|
19
19
|
- **CJS + ESM**: Dual build via tsup, works everywhere
|
|
20
20
|
- **Subpath imports**: `shrike-guard/openai`, `shrike-guard/anthropic`, `shrike-guard/gemini`
|
|
21
21
|
- **Zero code changes**: Just replace your import
|
|
22
22
|
|
|
23
23
|
## What Shrike Detects
|
|
24
24
|
|
|
25
|
-
Shrike's
|
|
25
|
+
Shrike's 9-layer cognitive pipeline includes sensitive-data detection aligned to 5 major regulatory frameworks:
|
|
26
26
|
|
|
27
27
|
| Framework | Coverage |
|
|
28
28
|
|-----------|----------|
|
|
@@ -31,10 +31,8 @@ Shrike's backend runs a multi-stage detection pipeline with security rules acros
|
|
|
31
31
|
| **ISO 27001** | Information security — passwords, tokens, certificates |
|
|
32
32
|
| **SOC 2** | Secrets, credentials, API keys, cloud tokens |
|
|
33
33
|
| **NIST** | AI risk management (IR 8596), cybersecurity framework (CSF 2.0) |
|
|
34
|
-
| **PCI-DSS** | Cardholder data — PAN, CVV, expiry, track data |
|
|
35
|
-
| **WebMCP** | MCP tool description injection, data exfiltration |
|
|
36
34
|
|
|
37
|
-
Plus built-in detection for prompt injection, jailbreaks, social engineering, and dangerous requests.
|
|
35
|
+
Detection coverage is not a certification claim — see [shrikesecurity.com/compliance](https://shrikesecurity.com/compliance) for our current certification status. Plus built-in detection for prompt injection, jailbreaks, social engineering, and dangerous requests.
|
|
38
36
|
|
|
39
37
|
### Tiers
|
|
40
38
|
|
|
@@ -42,7 +40,7 @@ Detection depth depends on your tier. All tiers get the same SDK wrappers — ti
|
|
|
42
40
|
|
|
43
41
|
| | Anonymous | Community | Pro | Enterprise |
|
|
44
42
|
|---|---|---|---|---|
|
|
45
|
-
| Detection Layers | L1-L5 | L1-L7 | L1-
|
|
43
|
+
| Detection Layers | L1-L5 | L1-L7 | L1-L9 (full) | L1-L9 (full) |
|
|
46
44
|
| API Key | Not needed | Free signup | Paid | Paid |
|
|
47
45
|
| Rate Limit | — | 10/min | 100/min | 1,000/min |
|
|
48
46
|
| Scans/month | — | 1,000 | 25,000 | 1,000,000 |
|
|
@@ -128,20 +126,22 @@ Choose how the SDK behaves when the security scan fails (timeout, network error,
|
|
|
128
126
|
```typescript
|
|
129
127
|
import { ShrikeOpenAI } from 'shrike-guard/openai';
|
|
130
128
|
|
|
131
|
-
// Fail-
|
|
132
|
-
// Best for:
|
|
129
|
+
// Fail-closed (default): Block requests if scan fails
|
|
130
|
+
// Best for: Production security workloads. If the Shrike backend is down,
|
|
131
|
+
// the SDK raises ShrikeScanError instead of allowing traffic through unguarded.
|
|
133
132
|
const client = new ShrikeOpenAI({
|
|
134
133
|
apiKey: 'sk-...',
|
|
135
134
|
shrikeApiKey: 'shrike-...',
|
|
136
|
-
failMode: '
|
|
135
|
+
failMode: 'closed', // This is the default
|
|
137
136
|
});
|
|
138
137
|
|
|
139
|
-
// Fail-
|
|
140
|
-
// Best for:
|
|
141
|
-
|
|
138
|
+
// Fail-open: Allow requests if scan fails
|
|
139
|
+
// Best for: Non-production experiments, internal tools where availability must
|
|
140
|
+
// outrank enforcement. Trades the guard's enforcement promise for uptime.
|
|
141
|
+
const permissiveClient = new ShrikeOpenAI({
|
|
142
142
|
apiKey: 'sk-...',
|
|
143
143
|
shrikeApiKey: 'shrike-...',
|
|
144
|
-
failMode: '
|
|
144
|
+
failMode: 'open',
|
|
145
145
|
});
|
|
146
146
|
```
|
|
147
147
|
|
|
@@ -302,9 +302,9 @@ Looking for an AI security SDK? Here's how Shrike Guard compares:
|
|
|
302
302
|
| Feature | Shrike Guard | Lakera | Prompt Armor |
|
|
303
303
|
|---|---|---|---|
|
|
304
304
|
| Drop-in OpenAI/Anthropic/Gemini wrapper | Yes | No | No |
|
|
305
|
-
|
|
|
305
|
+
| 9-layer cognitive pipeline | Yes | Limited | Limited |
|
|
306
306
|
| PII detection + redaction | Yes | Partial | No |
|
|
307
|
-
| Session correlation | Yes (
|
|
307
|
+
| Session correlation | Yes (Pro+) | No | No |
|
|
308
308
|
| Free tier (no API key) | Yes | No | No |
|
|
309
309
|
| Open source client | Yes (Apache 2.0) | No | No |
|
|
310
310
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
2
|
import { MessageCreateParams, Message } from '@anthropic-ai/sdk/resources/messages';
|
|
3
|
-
import { F as FailMode, S as ScanResult } from '../scanner-
|
|
3
|
+
import { F as FailMode, S as ScanResult } from '../scanner-RWQR_jcB.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* ShrikeAnthropic - Drop-in replacement for Anthropic client with security scanning.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
2
|
import { MessageCreateParams, Message } from '@anthropic-ai/sdk/resources/messages';
|
|
3
|
-
import { F as FailMode, S as ScanResult } from '../scanner-
|
|
3
|
+
import { F as FailMode, S as ScanResult } from '../scanner-RWQR_jcB.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* ShrikeAnthropic - Drop-in replacement for Anthropic client with security scanning.
|
package/dist/anthropic/index.js
CHANGED
|
@@ -74,9 +74,11 @@ var THREAT_TYPE_MAP = {
|
|
|
74
74
|
completion_baiting: "jailbreak",
|
|
75
75
|
override: "jailbreak",
|
|
76
76
|
manipulate: "jailbreak",
|
|
77
|
-
|
|
77
|
+
// L8 tonality drift — backend normalizes profanity + hostile as toxic_content;
|
|
78
|
+
// casual stays as jailbreak (matches platform/common/models/response.go:309-313).
|
|
79
|
+
tonality_drift_profanity: "toxic_content",
|
|
80
|
+
tonality_drift_hostile: "toxic_content",
|
|
78
81
|
tonality_drift_casual: "jailbreak",
|
|
79
|
-
tonality_drift_hostile: "jailbreak",
|
|
80
82
|
// System prompt leak
|
|
81
83
|
system_prompt_leak: "system_prompt_leak",
|
|
82
84
|
system_prompt_extraction: "system_prompt_leak",
|
|
@@ -132,9 +134,11 @@ var THREAT_TYPE_MAP = {
|
|
|
132
134
|
suspicious_tld: "blocked_domain",
|
|
133
135
|
suspicious_domain: "blocked_domain",
|
|
134
136
|
malicious_url: "blocked_domain",
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
// Toxic content (canonical name as of the L7 rewrite). `toxicity` kept as a
|
|
138
|
+
// legacy alias so older backend builds + customer code don't break.
|
|
139
|
+
toxic_content: "toxic_content",
|
|
140
|
+
toxicity: "toxic_content",
|
|
141
|
+
harmful_content: "toxic_content",
|
|
138
142
|
// Malicious code
|
|
139
143
|
malicious_content: "malicious_code",
|
|
140
144
|
malicious_code: "malicious_code",
|
|
@@ -155,6 +159,12 @@ var THREAT_TYPE_MAP = {
|
|
|
155
159
|
privilege_escalation: "privilege_escalation",
|
|
156
160
|
// Destructive operation
|
|
157
161
|
destructive_operation: "destructive_operation",
|
|
162
|
+
// L9 multi-turn correlation — the pseudo-category emitted when any
|
|
163
|
+
// multi_turn_* pattern fires (crescendo, blocked_retry, trust-building,
|
|
164
|
+
// memory_poisoning, etc.). The normalizeThreatType prefix check below
|
|
165
|
+
// handles the specific pattern names; this entry catches the pseudo
|
|
166
|
+
// value if the backend pre-normalizes.
|
|
167
|
+
multi_turn_attack: "multi_turn_attack",
|
|
158
168
|
// Errors
|
|
159
169
|
scan_error: "scan_error",
|
|
160
170
|
size_limit_exceeded: "size_limit_exceeded",
|
|
@@ -171,7 +181,9 @@ var THREAT_GUIDANCE = {
|
|
|
171
181
|
secrets_exposure: "This content contains patterns matching API keys, tokens, or credentials.",
|
|
172
182
|
pii_exposure: "This content contains personally identifiable information.",
|
|
173
183
|
blocked_domain: "This web search targets a restricted domain.",
|
|
184
|
+
toxic_content: "This content contains potentially harmful or inappropriate language.",
|
|
174
185
|
toxicity: "This content contains potentially harmful or inappropriate language.",
|
|
186
|
+
multi_turn_attack: "A pattern was detected across multiple turns of this session that suggests a coordinated attempt to bypass safety controls.",
|
|
175
187
|
malicious_code: "This content contains patterns associated with malicious code.",
|
|
176
188
|
harmful_intent: "This request contains content associated with harmful intent.",
|
|
177
189
|
social_engineering: "This prompt contains social engineering patterns.",
|
|
@@ -191,7 +203,9 @@ var THREAT_SEVERITY = {
|
|
|
191
203
|
secrets_exposure: "critical",
|
|
192
204
|
pii_exposure: "high",
|
|
193
205
|
blocked_domain: "medium",
|
|
206
|
+
toxic_content: "medium",
|
|
194
207
|
toxicity: "medium",
|
|
208
|
+
multi_turn_attack: "high",
|
|
195
209
|
malicious_code: "critical",
|
|
196
210
|
harmful_intent: "high",
|
|
197
211
|
social_engineering: "medium",
|
|
@@ -201,12 +215,31 @@ var THREAT_SEVERITY = {
|
|
|
201
215
|
size_limit_exceeded: "low",
|
|
202
216
|
unknown: "medium"
|
|
203
217
|
};
|
|
218
|
+
var INTERNAL_FIELDS = /* @__PURE__ */ new Set([
|
|
219
|
+
"detected_by",
|
|
220
|
+
"policy_id",
|
|
221
|
+
"policy_name",
|
|
222
|
+
"matched_pattern",
|
|
223
|
+
"matched_text",
|
|
224
|
+
"pattern",
|
|
225
|
+
"scan_stage",
|
|
226
|
+
"ai_reasoning",
|
|
227
|
+
"llm_analysis",
|
|
228
|
+
"performance_metrics",
|
|
229
|
+
"performance"
|
|
230
|
+
]);
|
|
204
231
|
function normalizeThreatType(rawType) {
|
|
205
232
|
if (!rawType) {
|
|
206
233
|
return "unknown";
|
|
207
234
|
}
|
|
208
235
|
const normalized = rawType.toLowerCase().replace(/-/g, "_");
|
|
209
|
-
|
|
236
|
+
if (THREAT_TYPE_MAP[normalized]) {
|
|
237
|
+
return THREAT_TYPE_MAP[normalized];
|
|
238
|
+
}
|
|
239
|
+
if (normalized.startsWith("multi_turn_")) {
|
|
240
|
+
return "multi_turn_attack";
|
|
241
|
+
}
|
|
242
|
+
return "unknown";
|
|
210
243
|
}
|
|
211
244
|
function deriveSeverity(threatType, rawSeverity) {
|
|
212
245
|
const validSeverities = /* @__PURE__ */ new Set(["critical", "high", "medium", "low"]);
|
|
@@ -227,20 +260,59 @@ function bucketConfidence(score) {
|
|
|
227
260
|
}
|
|
228
261
|
return "low";
|
|
229
262
|
}
|
|
263
|
+
var PRESERVED_GOVERNANCE_FIELDS = [
|
|
264
|
+
"action",
|
|
265
|
+
"refuse_tier",
|
|
266
|
+
"recovery",
|
|
267
|
+
"session_state",
|
|
268
|
+
"content_type",
|
|
269
|
+
"approval_info",
|
|
270
|
+
"client_session_rotation"
|
|
271
|
+
];
|
|
272
|
+
function sanitizeViolation(raw) {
|
|
273
|
+
if (!raw || typeof raw !== "object") {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
const source = raw;
|
|
277
|
+
const out = {};
|
|
278
|
+
for (const [k, v] of Object.entries(source)) {
|
|
279
|
+
if (!INTERNAL_FIELDS.has(k)) {
|
|
280
|
+
out[k] = v;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return out;
|
|
284
|
+
}
|
|
230
285
|
function sanitizeScanResponse(raw) {
|
|
231
286
|
const safe = raw.safe !== false;
|
|
232
|
-
const
|
|
287
|
+
const result = { safe };
|
|
288
|
+
for (const field of PRESERVED_GOVERNANCE_FIELDS) {
|
|
289
|
+
const value = raw[field];
|
|
290
|
+
if (value !== void 0 && value !== null) {
|
|
291
|
+
result[field] = value;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const rawViolations = raw.violations;
|
|
295
|
+
if (Array.isArray(rawViolations) && rawViolations.length > 0) {
|
|
296
|
+
const cleaned = rawViolations.map((v) => sanitizeViolation(v)).filter((v) => v !== null);
|
|
297
|
+
if (cleaned.length > 0) {
|
|
298
|
+
result.violations = cleaned;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
233
301
|
if (safe) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
302
|
+
result.reason = raw.reason || "";
|
|
303
|
+
return result;
|
|
304
|
+
}
|
|
305
|
+
let rawThreatType = raw.threat_type;
|
|
306
|
+
if (!rawThreatType && Array.isArray(rawViolations) && rawViolations.length > 0) {
|
|
307
|
+
const first = rawViolations[0];
|
|
308
|
+
if (first && typeof first === "object" && !Array.isArray(first)) {
|
|
309
|
+
const firstThreat = first.threat_type;
|
|
310
|
+
if (typeof firstThreat === "string") {
|
|
311
|
+
rawThreatType = firstThreat;
|
|
312
|
+
}
|
|
240
313
|
}
|
|
241
|
-
return result2;
|
|
242
314
|
}
|
|
243
|
-
const threatType = normalizeThreatType(
|
|
315
|
+
const threatType = normalizeThreatType(rawThreatType);
|
|
244
316
|
const confidence = bucketConfidence(
|
|
245
317
|
typeof raw.confidence === "number" ? raw.confidence : void 0
|
|
246
318
|
);
|
|
@@ -249,22 +321,16 @@ function sanitizeScanResponse(raw) {
|
|
|
249
321
|
typeof raw.severity === "string" ? raw.severity : void 0
|
|
250
322
|
);
|
|
251
323
|
const guidance = THREAT_GUIDANCE[threatType] || THREAT_GUIDANCE["unknown"];
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
reason: raw.reason || guidance,
|
|
258
|
-
guidance
|
|
259
|
-
};
|
|
260
|
-
if (approvalInfo) {
|
|
261
|
-
result.approval_info = approvalInfo;
|
|
262
|
-
}
|
|
324
|
+
result.threat_type = threatType;
|
|
325
|
+
result.severity = severity;
|
|
326
|
+
result.confidence = confidence;
|
|
327
|
+
result.reason = raw.reason || guidance;
|
|
328
|
+
result.guidance = guidance;
|
|
263
329
|
return result;
|
|
264
330
|
}
|
|
265
331
|
|
|
266
332
|
// src/version.ts
|
|
267
|
-
var VERSION = "1.
|
|
333
|
+
var VERSION = "1.5.0";
|
|
268
334
|
function generateUUID() {
|
|
269
335
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
270
336
|
const r = Math.random() * 16 | 0;
|
|
@@ -281,6 +347,18 @@ function getScanHeaders(shrikeApiKey, requestId) {
|
|
|
281
347
|
"X-Shrike-Request-ID": generateUUID()
|
|
282
348
|
};
|
|
283
349
|
}
|
|
350
|
+
function isBlocked(verdict) {
|
|
351
|
+
const action = verdict.action;
|
|
352
|
+
if (typeof action === "string" && action.length > 0) {
|
|
353
|
+
if (action === "allow" || action === "warn") return false;
|
|
354
|
+
if (action === "block" || action === "require_approval") return true;
|
|
355
|
+
}
|
|
356
|
+
const safe = verdict.safe;
|
|
357
|
+
if (typeof safe === "boolean") {
|
|
358
|
+
return !safe;
|
|
359
|
+
}
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
284
362
|
function maybeAddSignupHint(result, apiKey) {
|
|
285
363
|
if (apiKey) return result;
|
|
286
364
|
if (result.upgrade_hint) return result;
|
|
@@ -353,7 +431,7 @@ var ShrikeAnthropic = class {
|
|
|
353
431
|
const controller = new AbortController();
|
|
354
432
|
const timeoutId = setTimeout(() => controller.abort(), this._scanTimeout);
|
|
355
433
|
try {
|
|
356
|
-
const response = await fetch(`${this._shrikeEndpoint}/scan`, {
|
|
434
|
+
const response = await fetch(`${this._shrikeEndpoint}/api/scan/enforce`, {
|
|
357
435
|
method: "POST",
|
|
358
436
|
headers: getScanHeaders(this._shrikeApiKey),
|
|
359
437
|
body: JSON.stringify({
|
|
@@ -412,7 +490,7 @@ var MessagesNamespace = class {
|
|
|
412
490
|
const scanResult = await this._client._scanMessages(
|
|
413
491
|
params.messages
|
|
414
492
|
);
|
|
415
|
-
if (
|
|
493
|
+
if (isBlocked(scanResult)) {
|
|
416
494
|
throw new ShrikeBlockedError(
|
|
417
495
|
`Request blocked: ${scanResult.reason || "Security threat detected"}`,
|
|
418
496
|
scanResult.threat_type,
|