visus-mcp 0.2.0 → 0.6.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/.claude/settings.local.json +22 -0
- package/LINKEDIN-STRATEGY.md +367 -0
- package/README.md +491 -16
- package/ROADMAP.md +214 -34
- package/SECURITY-AUDIT-v1.md +277 -0
- package/STATUS.md +801 -42
- package/TROUBLESHOOT-AUTH-20260322-2019.md +291 -0
- package/TROUBLESHOOT-JEST-20260323-1357.md +139 -0
- package/TROUBLESHOOT-LAMBDA-20260322-1945.md +183 -0
- package/VISUS-CLAUDE-CODE-PROMPT.md +1 -1
- package/VISUS-PROJECT-PLAN.md +7 -0
- package/dist/browser/playwright-renderer.d.ts.map +1 -1
- package/dist/browser/playwright-renderer.js +7 -0
- package/dist/browser/playwright-renderer.js.map +1 -1
- package/dist/browser/reader.d.ts +31 -0
- package/dist/browser/reader.d.ts.map +1 -0
- package/dist/browser/reader.js +98 -0
- package/dist/browser/reader.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -5
- package/dist/index.js.map +1 -1
- package/dist/lambda-handler.d.ts +0 -6
- package/dist/lambda-handler.d.ts.map +1 -1
- package/dist/lambda-handler.js +97 -25
- package/dist/lambda-handler.js.map +1 -1
- package/dist/sanitizer/framework-mapper.d.ts +22 -0
- package/dist/sanitizer/framework-mapper.d.ts.map +1 -0
- package/dist/sanitizer/framework-mapper.js +296 -0
- package/dist/sanitizer/framework-mapper.js.map +1 -0
- package/dist/sanitizer/index.d.ts +10 -2
- package/dist/sanitizer/index.d.ts.map +1 -1
- package/dist/sanitizer/index.js +22 -6
- package/dist/sanitizer/index.js.map +1 -1
- package/dist/sanitizer/patterns.js +1 -1
- package/dist/sanitizer/patterns.js.map +1 -1
- package/dist/sanitizer/pii-allowlist.d.ts +49 -0
- package/dist/sanitizer/pii-allowlist.d.ts.map +1 -0
- package/dist/sanitizer/pii-allowlist.js +231 -0
- package/dist/sanitizer/pii-allowlist.js.map +1 -0
- package/dist/sanitizer/pii-redactor.d.ts +13 -1
- package/dist/sanitizer/pii-redactor.d.ts.map +1 -1
- package/dist/sanitizer/pii-redactor.js +26 -2
- package/dist/sanitizer/pii-redactor.js.map +1 -1
- package/dist/sanitizer/severity-classifier.d.ts +33 -0
- package/dist/sanitizer/severity-classifier.d.ts.map +1 -0
- package/dist/sanitizer/severity-classifier.js +113 -0
- package/dist/sanitizer/severity-classifier.js.map +1 -0
- package/dist/sanitizer/threat-reporter.d.ts +65 -0
- package/dist/sanitizer/threat-reporter.d.ts.map +1 -0
- package/dist/sanitizer/threat-reporter.js +160 -0
- package/dist/sanitizer/threat-reporter.js.map +1 -0
- package/dist/tools/fetch-structured.d.ts +5 -0
- package/dist/tools/fetch-structured.d.ts.map +1 -1
- package/dist/tools/fetch-structured.js +59 -8
- package/dist/tools/fetch-structured.js.map +1 -1
- package/dist/tools/fetch.d.ts +5 -0
- package/dist/tools/fetch.d.ts.map +1 -1
- package/dist/tools/fetch.js +43 -9
- package/dist/tools/fetch.js.map +1 -1
- package/dist/tools/read.d.ts +51 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +127 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/search.d.ts +45 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +220 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/format-converter.d.ts +39 -0
- package/dist/utils/format-converter.d.ts.map +1 -0
- package/dist/utils/format-converter.js +191 -0
- package/dist/utils/format-converter.js.map +1 -0
- package/dist/utils/truncate.d.ts +26 -0
- package/dist/utils/truncate.d.ts.map +1 -0
- package/dist/utils/truncate.js +54 -0
- package/dist/utils/truncate.js.map +1 -0
- package/infrastructure/stack.ts +55 -6
- package/jest.config.js +3 -0
- package/package.json +9 -2
- package/src/browser/playwright-renderer.ts +8 -0
- package/src/browser/reader.ts +129 -0
- package/src/index.ts +49 -5
- package/src/lambda-handler.ts +131 -26
- package/src/sanitizer/framework-mapper.ts +347 -0
- package/src/sanitizer/index.ts +28 -6
- package/src/sanitizer/patterns.ts +1 -1
- package/src/sanitizer/pii-allowlist.ts +273 -0
- package/src/sanitizer/pii-redactor.ts +43 -2
- package/src/sanitizer/severity-classifier.ts +132 -0
- package/src/sanitizer/threat-reporter.ts +261 -0
- package/src/tools/fetch-structured.ts +63 -8
- package/src/tools/fetch.ts +45 -9
- package/src/tools/read.ts +143 -0
- package/src/tools/search.ts +263 -0
- package/src/types.ts +71 -0
- package/src/utils/format-converter.ts +236 -0
- package/src/utils/truncate.ts +64 -0
- package/tests/auth-smoke.test.ts +480 -0
- package/tests/fetch-tool.test.ts +595 -2
- package/tests/pii-allowlist.test.ts +282 -0
- package/tests/reader.test.ts +353 -0
- package/tests/sanitizer.test.ts +52 -0
- package/tests/search.test.ts +456 -0
- package/tests/threat-reporter.test.ts +266 -0
package/src/index.ts
CHANGED
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
|
|
28
28
|
import { visusFetch, visusFetchToolDefinition } from './tools/fetch.js';
|
|
29
29
|
import { visusFetchStructured, visusFetchStructuredToolDefinition } from './tools/fetch-structured.js';
|
|
30
|
+
import { visusRead, visusReadToolDefinition } from './tools/read.js';
|
|
31
|
+
import { visusSearch, visusSearchToolDefinition } from './tools/search.js';
|
|
30
32
|
import { closeBrowser } from './browser/playwright-renderer.js';
|
|
31
33
|
import { detectRuntime, logRuntimeConfig, validateRuntime } from './runtime.js';
|
|
32
34
|
|
|
@@ -52,7 +54,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
52
54
|
return {
|
|
53
55
|
tools: [
|
|
54
56
|
visusFetchToolDefinition,
|
|
55
|
-
visusFetchStructuredToolDefinition
|
|
57
|
+
visusFetchStructuredToolDefinition,
|
|
58
|
+
visusReadToolDefinition,
|
|
59
|
+
visusSearchToolDefinition
|
|
56
60
|
]
|
|
57
61
|
};
|
|
58
62
|
});
|
|
@@ -105,6 +109,46 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
105
109
|
};
|
|
106
110
|
}
|
|
107
111
|
|
|
112
|
+
case 'visus_read': {
|
|
113
|
+
const result = await visusRead(args as any);
|
|
114
|
+
|
|
115
|
+
if (!result.ok) {
|
|
116
|
+
throw new McpError(
|
|
117
|
+
ErrorCode.InternalError,
|
|
118
|
+
`visus_read failed: ${result.error.message}`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
content: [
|
|
124
|
+
{
|
|
125
|
+
type: 'text',
|
|
126
|
+
text: JSON.stringify(result.value, null, 2)
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
case 'visus_search': {
|
|
133
|
+
const result = await visusSearch(args as any);
|
|
134
|
+
|
|
135
|
+
if (!result.ok) {
|
|
136
|
+
throw new McpError(
|
|
137
|
+
ErrorCode.InternalError,
|
|
138
|
+
`visus_search failed: ${result.error.message}`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
content: [
|
|
144
|
+
{
|
|
145
|
+
type: 'text',
|
|
146
|
+
text: JSON.stringify(result.value, null, 2)
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
108
152
|
default:
|
|
109
153
|
throw new McpError(
|
|
110
154
|
ErrorCode.MethodNotFound,
|
|
@@ -138,7 +182,7 @@ async function startMcpServer() {
|
|
|
138
182
|
event: 'mcp_server_started',
|
|
139
183
|
name: 'visus-mcp',
|
|
140
184
|
version: '0.2.0',
|
|
141
|
-
tools: ['visus_fetch', 'visus_fetch_structured']
|
|
185
|
+
tools: ['visus_fetch', 'visus_fetch_structured', 'visus_read', 'visus_search']
|
|
142
186
|
}));
|
|
143
187
|
|
|
144
188
|
// Graceful shutdown
|
|
@@ -188,9 +232,9 @@ async function main() {
|
|
|
188
232
|
}
|
|
189
233
|
}
|
|
190
234
|
|
|
191
|
-
// Export Lambda
|
|
192
|
-
//
|
|
193
|
-
export { handler
|
|
235
|
+
// Export Lambda handler (for AWS deployment)
|
|
236
|
+
// This is only used when the file is imported as a module by Lambda runtime
|
|
237
|
+
export { handler } from './lambda-handler.js';
|
|
194
238
|
|
|
195
239
|
// Run stdio MCP server when executed directly (not in Lambda)
|
|
196
240
|
if (!process.env.AWS_LAMBDA_FUNCTION_NAME) {
|
package/src/lambda-handler.ts
CHANGED
|
@@ -14,10 +14,16 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import type { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
|
17
|
+
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
18
|
+
import { DynamoDBDocumentClient, PutCommand } from '@aws-sdk/lib-dynamodb';
|
|
17
19
|
import { visusFetch } from './tools/fetch.js';
|
|
18
20
|
import { visusFetchStructured } from './tools/fetch-structured.js';
|
|
19
21
|
import { closeBrowser } from './browser/playwright-renderer.js';
|
|
20
22
|
|
|
23
|
+
// Initialize DynamoDB client
|
|
24
|
+
const ddbClient = new DynamoDBClient({});
|
|
25
|
+
const docClient = DynamoDBDocumentClient.from(ddbClient);
|
|
26
|
+
|
|
21
27
|
/**
|
|
22
28
|
* API request body for visus_fetch
|
|
23
29
|
*/
|
|
@@ -36,6 +42,63 @@ interface FetchStructuredRequest {
|
|
|
36
42
|
timeout_ms?: number;
|
|
37
43
|
}
|
|
38
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Fire-and-forget audit logging to DynamoDB
|
|
47
|
+
*
|
|
48
|
+
* Logs request metadata without blocking the response.
|
|
49
|
+
* Errors are logged but do not affect the API response.
|
|
50
|
+
*
|
|
51
|
+
* @param userId User ID from Cognito JWT
|
|
52
|
+
* @param requestId AWS request ID
|
|
53
|
+
* @param url URL being fetched
|
|
54
|
+
* @param endpoint API endpoint (/fetch or /fetch-structured)
|
|
55
|
+
* @param patternsDetected Sanitization patterns detected
|
|
56
|
+
* @param piiRedacted PII types redacted
|
|
57
|
+
*/
|
|
58
|
+
function logAuditEvent(
|
|
59
|
+
userId: string,
|
|
60
|
+
requestId: string,
|
|
61
|
+
url: string,
|
|
62
|
+
endpoint: string,
|
|
63
|
+
patternsDetected: string[],
|
|
64
|
+
piiRedacted: string[]
|
|
65
|
+
): void {
|
|
66
|
+
const tableName = process.env.AUDIT_TABLE_NAME;
|
|
67
|
+
|
|
68
|
+
if (!tableName) {
|
|
69
|
+
console.error('AUDIT_TABLE_NAME not set - skipping audit logging');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const now = new Date();
|
|
74
|
+
const ttl = Math.floor(now.getTime() / 1000) + (30 * 24 * 60 * 60); // 30 days from now
|
|
75
|
+
|
|
76
|
+
const item = {
|
|
77
|
+
user_id: userId,
|
|
78
|
+
timestamp: now.toISOString(),
|
|
79
|
+
request_id: requestId,
|
|
80
|
+
url,
|
|
81
|
+
endpoint,
|
|
82
|
+
patterns_detected: patternsDetected,
|
|
83
|
+
pii_redacted: piiRedacted,
|
|
84
|
+
ttl, // Auto-delete after 30 days
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Fire-and-forget: do not await
|
|
88
|
+
docClient.send(new PutCommand({
|
|
89
|
+
TableName: tableName,
|
|
90
|
+
Item: item,
|
|
91
|
+
})).catch((error: unknown) => {
|
|
92
|
+
// Log error but do not throw (fire-and-forget pattern)
|
|
93
|
+
console.error(JSON.stringify({
|
|
94
|
+
timestamp: now.toISOString(),
|
|
95
|
+
event: 'audit_logging_failed',
|
|
96
|
+
error: error instanceof Error ? error.message : String(error),
|
|
97
|
+
request_id: requestId,
|
|
98
|
+
}));
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
39
102
|
/**
|
|
40
103
|
* Lambda handler for Visus API
|
|
41
104
|
*
|
|
@@ -65,10 +128,14 @@ export async function handler(
|
|
|
65
128
|
}));
|
|
66
129
|
|
|
67
130
|
try {
|
|
68
|
-
// CORS headers for all responses
|
|
131
|
+
// CORS headers for all responses (environment-variable-driven allowlist)
|
|
132
|
+
const allowedOrigins = (process.env.ALLOWED_ORIGINS || '*').split(',');
|
|
133
|
+
const origin = event.headers.origin || event.headers.Origin || '';
|
|
134
|
+
const allowOrigin = allowedOrigins.includes(origin) ? origin : allowedOrigins[0] || '*';
|
|
135
|
+
|
|
69
136
|
const corsHeaders = {
|
|
70
|
-
'Access-Control-Allow-Origin':
|
|
71
|
-
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
137
|
+
'Access-Control-Allow-Origin': allowOrigin,
|
|
138
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
72
139
|
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
73
140
|
'Content-Type': 'application/json',
|
|
74
141
|
};
|
|
@@ -82,7 +149,22 @@ export async function handler(
|
|
|
82
149
|
};
|
|
83
150
|
}
|
|
84
151
|
|
|
85
|
-
//
|
|
152
|
+
// Health check endpoint (no auth required, allows GET and POST)
|
|
153
|
+
// SECURITY FIX (FINDING 2): Moved before POST-only validation to support standard GET health checks
|
|
154
|
+
if (event.path === '/health' || event.path === '/dev/health' || event.path === '/prod/health') {
|
|
155
|
+
return {
|
|
156
|
+
statusCode: 200,
|
|
157
|
+
headers: corsHeaders,
|
|
158
|
+
body: JSON.stringify({
|
|
159
|
+
status: 'healthy',
|
|
160
|
+
service: 'visus-mcp',
|
|
161
|
+
version: '0.3.1',
|
|
162
|
+
timestamp: new Date().toISOString(),
|
|
163
|
+
}),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Only allow POST requests for protected endpoints
|
|
86
168
|
if (event.httpMethod !== 'POST') {
|
|
87
169
|
return {
|
|
88
170
|
statusCode: 405,
|
|
@@ -103,8 +185,31 @@ export async function handler(
|
|
|
103
185
|
};
|
|
104
186
|
}
|
|
105
187
|
|
|
188
|
+
// SECURITY FIX (FINDING 1): Application-level authentication enforcement
|
|
189
|
+
// Extract user ID from Cognito authorizer
|
|
190
|
+
const userId = event.requestContext.authorizer?.claims?.sub;
|
|
191
|
+
|
|
192
|
+
// Require authentication for all protected endpoints (not already handled above)
|
|
193
|
+
if (!userId) {
|
|
194
|
+
console.error(JSON.stringify({
|
|
195
|
+
timestamp: new Date().toISOString(),
|
|
196
|
+
event: 'auth_required',
|
|
197
|
+
request_id: requestId,
|
|
198
|
+
path: event.path,
|
|
199
|
+
reason: 'Missing Cognito authorizer context - Lambda must be invoked via API Gateway',
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
statusCode: 401,
|
|
204
|
+
headers: corsHeaders,
|
|
205
|
+
body: JSON.stringify({
|
|
206
|
+
error: 'Unauthorized: Authentication required. This Lambda must be invoked via API Gateway with Cognito authorizer.',
|
|
207
|
+
}),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
106
211
|
// Route based on path
|
|
107
|
-
if (event.path === '/fetch' || event.path === '/prod/fetch') {
|
|
212
|
+
if (event.path === '/fetch' || event.path === '/dev/fetch' || event.path === '/prod/fetch') {
|
|
108
213
|
const fetchReq = body as FetchRequest;
|
|
109
214
|
|
|
110
215
|
// Validate request
|
|
@@ -127,6 +232,16 @@ export async function handler(
|
|
|
127
232
|
};
|
|
128
233
|
}
|
|
129
234
|
|
|
235
|
+
// Fire-and-forget audit logging
|
|
236
|
+
logAuditEvent(
|
|
237
|
+
userId,
|
|
238
|
+
requestId,
|
|
239
|
+
fetchReq.url,
|
|
240
|
+
'/fetch',
|
|
241
|
+
result.value.sanitization.patterns_detected,
|
|
242
|
+
result.value.sanitization.pii_types_redacted
|
|
243
|
+
);
|
|
244
|
+
|
|
130
245
|
return {
|
|
131
246
|
statusCode: 200,
|
|
132
247
|
headers: corsHeaders,
|
|
@@ -134,7 +249,7 @@ export async function handler(
|
|
|
134
249
|
};
|
|
135
250
|
}
|
|
136
251
|
|
|
137
|
-
if (event.path === '/fetch-structured' || event.path === '/prod/fetch-structured') {
|
|
252
|
+
if (event.path === '/fetch-structured' || event.path === '/dev/fetch-structured' || event.path === '/prod/fetch-structured') {
|
|
138
253
|
const fetchReq = body as FetchStructuredRequest;
|
|
139
254
|
|
|
140
255
|
// Validate request
|
|
@@ -165,6 +280,16 @@ export async function handler(
|
|
|
165
280
|
};
|
|
166
281
|
}
|
|
167
282
|
|
|
283
|
+
// Fire-and-forget audit logging
|
|
284
|
+
logAuditEvent(
|
|
285
|
+
userId,
|
|
286
|
+
requestId,
|
|
287
|
+
fetchReq.url,
|
|
288
|
+
'/fetch-structured',
|
|
289
|
+
result.value.sanitization.patterns_detected,
|
|
290
|
+
result.value.sanitization.pii_types_redacted
|
|
291
|
+
);
|
|
292
|
+
|
|
168
293
|
return {
|
|
169
294
|
statusCode: 200,
|
|
170
295
|
headers: corsHeaders,
|
|
@@ -203,23 +328,3 @@ export async function handler(
|
|
|
203
328
|
await closeBrowser();
|
|
204
329
|
}
|
|
205
330
|
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Health check handler
|
|
209
|
-
*
|
|
210
|
-
* @returns API Gateway response
|
|
211
|
-
*/
|
|
212
|
-
export async function healthCheck(): Promise<APIGatewayProxyResult> {
|
|
213
|
-
return {
|
|
214
|
-
statusCode: 200,
|
|
215
|
-
headers: {
|
|
216
|
-
'Content-Type': 'application/json',
|
|
217
|
-
},
|
|
218
|
-
body: JSON.stringify({
|
|
219
|
-
status: 'healthy',
|
|
220
|
-
service: 'visus-mcp',
|
|
221
|
-
version: '0.2.0',
|
|
222
|
-
timestamp: new Date().toISOString(),
|
|
223
|
-
}),
|
|
224
|
-
};
|
|
225
|
-
}
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance Framework Mapper
|
|
3
|
+
*
|
|
4
|
+
* Maps injection pattern categories to compliance framework identifiers:
|
|
5
|
+
* - OWASP LLM Top 10 (2025)
|
|
6
|
+
* - NIST AI 600-1 (Generative AI Profile)
|
|
7
|
+
* - MITRE ATLAS (Adversarial Threat Landscape for AI Systems)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface FrameworkMappings {
|
|
11
|
+
owasp_llm: string;
|
|
12
|
+
nist_ai_600_1: string;
|
|
13
|
+
mitre_atlas: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Pattern category to framework mapping
|
|
18
|
+
*/
|
|
19
|
+
const FRAMEWORK_MAP: Record<string, FrameworkMappings> = {
|
|
20
|
+
// Direct instruction injection
|
|
21
|
+
direct_instruction_injection: {
|
|
22
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
23
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
24
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// Role hijacking
|
|
28
|
+
role_hijacking: {
|
|
29
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
30
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
31
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
// System prompt extraction
|
|
35
|
+
system_prompt_extraction: {
|
|
36
|
+
owasp_llm: 'LLM02:2025 - Sensitive Information Disclosure',
|
|
37
|
+
nist_ai_600_1: 'MS-2.6 - Data Disclosure',
|
|
38
|
+
mitre_atlas: 'AML.T0048 - External Harms'
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
// Privilege escalation
|
|
42
|
+
privilege_escalation: {
|
|
43
|
+
owasp_llm: 'LLM08:2025 - Excessive Agency',
|
|
44
|
+
nist_ai_600_1: 'GV-1.1 - Policies and Procedures',
|
|
45
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Context poisoning
|
|
49
|
+
context_poisoning: {
|
|
50
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
51
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
52
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// Data exfiltration
|
|
56
|
+
data_exfiltration: {
|
|
57
|
+
owasp_llm: 'LLM02:2025 - Sensitive Information Disclosure',
|
|
58
|
+
nist_ai_600_1: 'MS-2.6 - Data Disclosure',
|
|
59
|
+
mitre_atlas: 'AML.T0048 - External Harms'
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Encoding obfuscation
|
|
63
|
+
base64_obfuscation: {
|
|
64
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
65
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
66
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// Unicode lookalikes
|
|
70
|
+
unicode_lookalikes: {
|
|
71
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
72
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
73
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
// Zero-width characters
|
|
77
|
+
zero_width_characters: {
|
|
78
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
79
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
80
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// HTML script injection
|
|
84
|
+
html_script_injection: {
|
|
85
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
86
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
87
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Data URI injection
|
|
91
|
+
data_uri_injection: {
|
|
92
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
93
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
94
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
// Markdown link injection
|
|
98
|
+
markdown_link_injection: {
|
|
99
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
100
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
101
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// URL fragment attacks
|
|
105
|
+
url_fragment_hashjack: {
|
|
106
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
107
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
108
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// Social engineering
|
|
112
|
+
social_engineering_urgency: {
|
|
113
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
114
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
115
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Instruction delimiter injection
|
|
119
|
+
instruction_delimiter_injection: {
|
|
120
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
121
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
122
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
// Multi-language obfuscation
|
|
126
|
+
multi_language_obfuscation: {
|
|
127
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
128
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
129
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
// Reverse text obfuscation
|
|
133
|
+
reverse_text_obfuscation: {
|
|
134
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
135
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
136
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
// Leetspeak obfuscation
|
|
140
|
+
leetspeak_obfuscation: {
|
|
141
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
142
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
143
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// Jailbreak keywords
|
|
147
|
+
jailbreak_keywords: {
|
|
148
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
149
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
150
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
// Token smuggling
|
|
154
|
+
token_smuggling: {
|
|
155
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
156
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
157
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// System message injection
|
|
161
|
+
system_message_injection: {
|
|
162
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
163
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
164
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
// Conversation reset
|
|
168
|
+
conversation_reset: {
|
|
169
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
170
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
171
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
// Memory manipulation
|
|
175
|
+
memory_manipulation: {
|
|
176
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
177
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
178
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
// Capability probing
|
|
182
|
+
capability_probing: {
|
|
183
|
+
owasp_llm: 'LLM08:2025 - Excessive Agency',
|
|
184
|
+
nist_ai_600_1: 'GV-1.1 - Policies and Procedures',
|
|
185
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
// Chain-of-thought manipulation
|
|
189
|
+
chain_of_thought_manipulation: {
|
|
190
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
191
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
192
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
// Hypothetical scenario injection
|
|
196
|
+
hypothetical_scenario_injection: {
|
|
197
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
198
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
199
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// Ethical override
|
|
203
|
+
ethical_override: {
|
|
204
|
+
owasp_llm: 'LLM08:2025 - Excessive Agency',
|
|
205
|
+
nist_ai_600_1: 'GV-1.1 - Policies and Procedures',
|
|
206
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
// Output format manipulation
|
|
210
|
+
output_format_manipulation: {
|
|
211
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
212
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
213
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
// Negative instruction
|
|
217
|
+
negative_instruction: {
|
|
218
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
219
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
220
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
// Credential harvesting
|
|
224
|
+
credential_harvesting: {
|
|
225
|
+
owasp_llm: 'LLM02:2025 - Sensitive Information Disclosure',
|
|
226
|
+
nist_ai_600_1: 'MS-2.6 - Data Disclosure',
|
|
227
|
+
mitre_atlas: 'AML.T0048 - External Harms'
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
// Time-based triggers
|
|
231
|
+
time_based_triggers: {
|
|
232
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
233
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
234
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
// Code execution requests
|
|
238
|
+
code_execution_requests: {
|
|
239
|
+
owasp_llm: 'LLM08:2025 - Excessive Agency',
|
|
240
|
+
nist_ai_600_1: 'GV-1.1 - Policies and Procedures',
|
|
241
|
+
mitre_atlas: 'AML.T0048 - External Harms'
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
// File system access
|
|
245
|
+
file_system_access: {
|
|
246
|
+
owasp_llm: 'LLM08:2025 - Excessive Agency',
|
|
247
|
+
nist_ai_600_1: 'GV-1.1 - Policies and Procedures',
|
|
248
|
+
mitre_atlas: 'AML.T0048 - External Harms'
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
// Training data extraction
|
|
252
|
+
training_data_extraction: {
|
|
253
|
+
owasp_llm: 'LLM02:2025 - Sensitive Information Disclosure',
|
|
254
|
+
nist_ai_600_1: 'MS-2.6 - Data Disclosure',
|
|
255
|
+
mitre_atlas: 'AML.T0048 - External Harms'
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
// Simulator mode
|
|
259
|
+
simulator_mode: {
|
|
260
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
261
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
262
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
// Nested encoding
|
|
266
|
+
nested_encoding: {
|
|
267
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
268
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
269
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
// Payload splitting
|
|
273
|
+
payload_splitting: {
|
|
274
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
275
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
276
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
// CSS-based hiding
|
|
280
|
+
css_hiding: {
|
|
281
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
282
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
283
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
// Authority impersonation
|
|
287
|
+
authority_impersonation: {
|
|
288
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
289
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
290
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
// Testing/debugging claims
|
|
294
|
+
testing_debugging_claims: {
|
|
295
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
296
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
297
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
// Callback URL injection
|
|
301
|
+
callback_url_injection: {
|
|
302
|
+
owasp_llm: 'LLM02:2025 - Sensitive Information Disclosure',
|
|
303
|
+
nist_ai_600_1: 'MS-2.6 - Data Disclosure',
|
|
304
|
+
mitre_atlas: 'AML.T0048 - External Harms'
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
// Whitespace steganography
|
|
308
|
+
whitespace_steganography: {
|
|
309
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
310
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
311
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
312
|
+
},
|
|
313
|
+
|
|
314
|
+
// Comment injection
|
|
315
|
+
comment_injection: {
|
|
316
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
317
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
318
|
+
mitre_atlas: 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Default mapping for unknown pattern categories
|
|
324
|
+
*/
|
|
325
|
+
const DEFAULT_MAPPINGS: FrameworkMappings = {
|
|
326
|
+
owasp_llm: 'LLM01:2025 - Prompt Injection',
|
|
327
|
+
nist_ai_600_1: 'MS-2.5 - Prompt Injection',
|
|
328
|
+
mitre_atlas: 'AML.T0051.000 - LLM Prompt Injection'
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Get framework mappings for a pattern category
|
|
333
|
+
*/
|
|
334
|
+
export function getFrameworkMappings(patternCategory: string): FrameworkMappings {
|
|
335
|
+
return FRAMEWORK_MAP[patternCategory] || DEFAULT_MAPPINGS;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Get all supported frameworks
|
|
340
|
+
*/
|
|
341
|
+
export function getSupportedFrameworks(): string[] {
|
|
342
|
+
return [
|
|
343
|
+
'OWASP LLM Top 10 (2025)',
|
|
344
|
+
'NIST AI 600-1 (Generative AI Profile)',
|
|
345
|
+
'MITRE ATLAS (Adversarial Threat Landscape)'
|
|
346
|
+
];
|
|
347
|
+
}
|