shrike-guard 1.3.1 → 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/LICENSE +2 -2
- package/README.md +82 -35
- package/dist/anthropic/index.d.mts +1 -1
- package/dist/anthropic/index.d.ts +1 -1
- package/dist/anthropic/index.js +109 -30
- package/dist/anthropic/index.js.map +1 -1
- package/dist/anthropic/index.mjs +109 -30
- 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 +2 -2
- package/dist/gemini/index.d.ts +2 -2
- package/dist/gemini/index.js +114 -35
- package/dist/gemini/index.js.map +1 -1
- package/dist/gemini/index.mjs +114 -35
- 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 +948 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +932 -34
- 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 +111 -32
- package/dist/openai/index.js.map +1 -1
- package/dist/openai/index.mjs +111 -32
- package/dist/openai/index.mjs.map +1 -1
- package/dist/scanner-RWQR_jcB.d.mts +306 -0
- package/dist/scanner-RWQR_jcB.d.ts +306 -0
- package/package.json +18 -13
- package/dist/scanner-Bz7j8OSD.d.mts +0 -166
- package/dist/scanner-Bz7j8OSD.d.ts +0 -166
package/LICENSE
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"Contribution" shall mean any work of authorship, including
|
|
49
49
|
the original version of the Work and any modifications or additions
|
|
50
50
|
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
-
submitted to
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
52
|
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
53
|
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
54
|
means any form of electronic, verbal, or written communication sent
|
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
package/README.md
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
# Shrike Guard
|
|
2
|
-
|
|
3
|
-
> **Public repo:** https://github.com/Shrike-Security/shrike-guard-js
|
|
4
|
-
>
|
|
5
|
-
> This directory is mirrored from the public repository. For the latest version, issues, and contributions, please use the public repo.
|
|
1
|
+
# Shrike Guard
|
|
6
2
|
|
|
7
3
|
[](https://badge.fury.io/js/shrike-guard)
|
|
8
4
|
[](https://nodejs.org/)
|
|
9
5
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
10
6
|
|
|
11
|
-
**Shrike Guard** is a TypeScript SDK
|
|
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.
|
|
12
8
|
|
|
13
9
|
## Features
|
|
14
10
|
|
|
@@ -19,11 +15,38 @@
|
|
|
19
15
|
- Jailbreak attempts
|
|
20
16
|
- SQL injection
|
|
21
17
|
- Path traversal
|
|
22
|
-
- **Fail-safe modes**:
|
|
18
|
+
- **Fail-safe modes**: Defaults to fail-closed (Zero Trust posture); opt into fail-open explicitly when availability outranks enforcement
|
|
23
19
|
- **CJS + ESM**: Dual build via tsup, works everywhere
|
|
24
20
|
- **Subpath imports**: `shrike-guard/openai`, `shrike-guard/anthropic`, `shrike-guard/gemini`
|
|
25
21
|
- **Zero code changes**: Just replace your import
|
|
26
22
|
|
|
23
|
+
## What Shrike Detects
|
|
24
|
+
|
|
25
|
+
Shrike's 9-layer cognitive pipeline includes sensitive-data detection aligned to 5 major regulatory frameworks:
|
|
26
|
+
|
|
27
|
+
| Framework | Coverage |
|
|
28
|
+
|-----------|----------|
|
|
29
|
+
| **GDPR** | EU personal data — names, addresses, national IDs |
|
|
30
|
+
| **HIPAA** | Protected health information (PHI) |
|
|
31
|
+
| **ISO 27001** | Information security — passwords, tokens, certificates |
|
|
32
|
+
| **SOC 2** | Secrets, credentials, API keys, cloud tokens |
|
|
33
|
+
| **NIST** | AI risk management (IR 8596), cybersecurity framework (CSF 2.0) |
|
|
34
|
+
|
|
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.
|
|
36
|
+
|
|
37
|
+
### Tiers
|
|
38
|
+
|
|
39
|
+
Detection depth depends on your tier. All tiers get the same SDK wrappers — tiers control which backend layers run.
|
|
40
|
+
|
|
41
|
+
| | Anonymous | Community | Pro | Enterprise |
|
|
42
|
+
|---|---|---|---|---|
|
|
43
|
+
| Detection Layers | L1-L5 | L1-L7 | L1-L9 (full) | L1-L9 (full) |
|
|
44
|
+
| API Key | Not needed | Free signup | Paid | Paid |
|
|
45
|
+
| Rate Limit | — | 10/min | 100/min | 1,000/min |
|
|
46
|
+
| Scans/month | — | 1,000 | 25,000 | 1,000,000 |
|
|
47
|
+
|
|
48
|
+
**Anonymous** (no API key): Pattern-based detection (L1-L5). **Community** (free): Adds LLM-powered semantic analysis. Register at [shrikesecurity.com/signup](https://shrikesecurity.com/signup) — instant, no credit card.
|
|
49
|
+
|
|
27
50
|
## Installation
|
|
28
51
|
|
|
29
52
|
```bash
|
|
@@ -103,20 +126,22 @@ Choose how the SDK behaves when the security scan fails (timeout, network error,
|
|
|
103
126
|
```typescript
|
|
104
127
|
import { ShrikeOpenAI } from 'shrike-guard/openai';
|
|
105
128
|
|
|
106
|
-
// Fail-
|
|
107
|
-
// 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.
|
|
108
132
|
const client = new ShrikeOpenAI({
|
|
109
133
|
apiKey: 'sk-...',
|
|
110
134
|
shrikeApiKey: 'shrike-...',
|
|
111
|
-
failMode: '
|
|
135
|
+
failMode: 'closed', // This is the default
|
|
112
136
|
});
|
|
113
137
|
|
|
114
|
-
// Fail-
|
|
115
|
-
// Best for:
|
|
116
|
-
|
|
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({
|
|
117
142
|
apiKey: 'sk-...',
|
|
118
143
|
shrikeApiKey: 'shrike-...',
|
|
119
|
-
failMode: '
|
|
144
|
+
failMode: 'open',
|
|
120
145
|
});
|
|
121
146
|
```
|
|
122
147
|
|
|
@@ -132,18 +157,16 @@ const client = new ShrikeOpenAI({
|
|
|
132
157
|
|
|
133
158
|
### Custom Endpoint
|
|
134
159
|
|
|
135
|
-
For
|
|
160
|
+
For self-hosted Shrike deployments:
|
|
136
161
|
|
|
137
162
|
```typescript
|
|
138
163
|
const client = new ShrikeOpenAI({
|
|
139
164
|
apiKey: 'sk-...',
|
|
140
165
|
shrikeApiKey: 'shrike-...',
|
|
141
|
-
shrikeEndpoint: 'https://your-
|
|
166
|
+
shrikeEndpoint: 'https://your-shrike-instance.com',
|
|
142
167
|
});
|
|
143
168
|
```
|
|
144
169
|
|
|
145
|
-
Dedicated endpoints are provisioned by Shrike during enterprise onboarding. Contact sales@shrikesecurity.com for details.
|
|
146
|
-
|
|
147
170
|
## SQL and File Scanning
|
|
148
171
|
|
|
149
172
|
The OpenAI client also provides standalone scanning for SQL queries and file paths:
|
|
@@ -233,20 +256,9 @@ if (result.safe) {
|
|
|
233
256
|
export OPENAI_API_KEY="sk-..."
|
|
234
257
|
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
235
258
|
export SHRIKE_API_KEY="shrike-..."
|
|
236
|
-
export SHRIKE_ENDPOINT="https://your-
|
|
259
|
+
export SHRIKE_ENDPOINT="https://your-shrike-instance.com"
|
|
237
260
|
```
|
|
238
261
|
|
|
239
|
-
## Pricing Tiers
|
|
240
|
-
|
|
241
|
-
| | Community (Free) | Pro ($99/mo) | Enterprise |
|
|
242
|
-
|---|---|---|---|
|
|
243
|
-
| Scans/month | 1,000 | 50,000 | Unlimited |
|
|
244
|
-
| Detection layers | L1-L4 (regex) | L1-L8 (full pipeline) | L1-L8 + custom |
|
|
245
|
-
| LLM analysis | No | Yes | Yes |
|
|
246
|
-
| Rate limit | 10 req/min | 100 req/min | 1,000 req/min |
|
|
247
|
-
|
|
248
|
-
Get a free Community API key at [shrikesecurity.com](https://api.shrikesecurity.com/dashboard/api/v1/community/register) or via [GCP Marketplace](https://console.cloud.google.com/marketplace/product/shrike-security/shrike).
|
|
249
|
-
|
|
250
262
|
## Scope and Limitations
|
|
251
263
|
|
|
252
264
|
| Scanned | Not Scanned |
|
|
@@ -258,10 +270,43 @@ Get a free Community API key at [shrikesecurity.com](https://api.shrikesecurity.
|
|
|
258
270
|
|
|
259
271
|
### Why Input-Only Scanning?
|
|
260
272
|
|
|
261
|
-
Shrike Guard focuses on **pre-flight protection**
|
|
273
|
+
Shrike Guard focuses on **pre-flight protection** — blocking malicious prompts BEFORE they reach the LLM. This:
|
|
262
274
|
- Prevents prompt injection attacks at the source
|
|
263
275
|
- Has zero latency impact on LLM responses
|
|
264
|
-
- Catches
|
|
276
|
+
- Catches the vast majority of threats at the input layer
|
|
277
|
+
|
|
278
|
+
## Other Integration Surfaces
|
|
279
|
+
|
|
280
|
+
Shrike Guard is one of several ways to integrate with the Shrike platform:
|
|
281
|
+
|
|
282
|
+
- **MCP Server** — `npx shrike-mcp` ([GitHub](https://github.com/Shrike-Security/shrike-mcp))
|
|
283
|
+
- **Python SDK** — `pip install shrike-guard` ([GitHub](https://github.com/Shrike-Security/shrike-guard-python))
|
|
284
|
+
- **REST API** — `POST https://api.shrikesecurity.com/agent/scan`
|
|
285
|
+
- **LLM Gateway** — Change one URL, scan everything
|
|
286
|
+
- **Browser Extension** — Chrome/Edge for ChatGPT, Claude, Gemini
|
|
287
|
+
- **Dashboard** — [shrikesecurity.com](https://shrikesecurity.com)
|
|
288
|
+
|
|
289
|
+
## Use Cases
|
|
290
|
+
|
|
291
|
+
| Scenario | How Shrike Guard Helps |
|
|
292
|
+
|---|---|
|
|
293
|
+
| **Customer chatbot** | Wrap your OpenAI/Anthropic client. Every user message scanned for injection before it reaches the model. |
|
|
294
|
+
| **Internal RAG pipeline** | Scan retrieved context + user queries for PII leakage and injection attempts. |
|
|
295
|
+
| **AI coding assistant** | Scan prompts for proprietary code patterns before they leave your environment. |
|
|
296
|
+
| **Agent orchestration** | Scan every tool call and LLM request in your LangChain/CrewAI/AutoGen pipeline. |
|
|
297
|
+
|
|
298
|
+
## Alternatives
|
|
299
|
+
|
|
300
|
+
Looking for an AI security SDK? Here's how Shrike Guard compares:
|
|
301
|
+
|
|
302
|
+
| Feature | Shrike Guard | Lakera | Prompt Armor |
|
|
303
|
+
|---|---|---|---|
|
|
304
|
+
| Drop-in OpenAI/Anthropic/Gemini wrapper | Yes | No | No |
|
|
305
|
+
| 9-layer cognitive pipeline | Yes | Limited | Limited |
|
|
306
|
+
| PII detection + redaction | Yes | Partial | No |
|
|
307
|
+
| Session correlation | Yes (Pro+) | No | No |
|
|
308
|
+
| Free tier (no API key) | Yes | No | No |
|
|
309
|
+
| Open source client | Yes (Apache 2.0) | No | No |
|
|
265
310
|
|
|
266
311
|
## License
|
|
267
312
|
|
|
@@ -269,6 +314,8 @@ Apache 2.0
|
|
|
269
314
|
|
|
270
315
|
## Support
|
|
271
316
|
|
|
272
|
-
-
|
|
273
|
-
-
|
|
274
|
-
-
|
|
317
|
+
- [Shrike](https://shrikesecurity.com) — Sign up, dashboard, docs
|
|
318
|
+
- [Documentation](https://shrikesecurity.com/docs) — Quick start, API reference
|
|
319
|
+
- [GitHub Issues](https://github.com/Shrike-Security/shrike-guard-js/issues) — Bug reports
|
|
320
|
+
- [MCP Server](https://github.com/Shrike-Security/shrike-mcp) — For MCP/agent integration
|
|
321
|
+
- [Python SDK](https://github.com/Shrike-Security/shrike-guard-python) — Python equivalent
|
|
@@ -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,11 +347,24 @@ 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;
|
|
364
|
+
if (result.upgrade_hint) return result;
|
|
286
365
|
return {
|
|
287
366
|
...result,
|
|
288
|
-
_note: "Running without API key (
|
|
367
|
+
_note: "Running without API key (L1-L5 only). Register free for cognitive threat detection: npx shrike-mcp --signup"
|
|
289
368
|
};
|
|
290
369
|
}
|
|
291
370
|
|
|
@@ -352,7 +431,7 @@ var ShrikeAnthropic = class {
|
|
|
352
431
|
const controller = new AbortController();
|
|
353
432
|
const timeoutId = setTimeout(() => controller.abort(), this._scanTimeout);
|
|
354
433
|
try {
|
|
355
|
-
const response = await fetch(`${this._shrikeEndpoint}/scan`, {
|
|
434
|
+
const response = await fetch(`${this._shrikeEndpoint}/api/scan/enforce`, {
|
|
356
435
|
method: "POST",
|
|
357
436
|
headers: getScanHeaders(this._shrikeApiKey),
|
|
358
437
|
body: JSON.stringify({
|
|
@@ -411,7 +490,7 @@ var MessagesNamespace = class {
|
|
|
411
490
|
const scanResult = await this._client._scanMessages(
|
|
412
491
|
params.messages
|
|
413
492
|
);
|
|
414
|
-
if (
|
|
493
|
+
if (isBlocked(scanResult)) {
|
|
415
494
|
throw new ShrikeBlockedError(
|
|
416
495
|
`Request blocked: ${scanResult.reason || "Security threat detected"}`,
|
|
417
496
|
scanResult.threat_type,
|