visus-mcp 0.6.2 → 0.9.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.
Files changed (203) hide show
  1. package/.claude/settings.local.json +15 -1
  2. package/.env.status +7 -0
  3. package/CHANGELOG.md +110 -0
  4. package/CLAUDE.md +3 -0
  5. package/README.md +29 -19
  6. package/SECURITY.md +2 -0
  7. package/STATUS.md +320 -12
  8. package/dist/browser/playwright-renderer.d.ts.map +1 -1
  9. package/dist/browser/playwright-renderer.js +27 -5
  10. package/dist/browser/playwright-renderer.js.map +1 -1
  11. package/dist/content-handlers/index.d.ts +36 -0
  12. package/dist/content-handlers/index.d.ts.map +1 -0
  13. package/dist/content-handlers/index.js +59 -0
  14. package/dist/content-handlers/index.js.map +1 -0
  15. package/dist/content-handlers/json-handler.d.ts +28 -0
  16. package/dist/content-handlers/json-handler.d.ts.map +1 -0
  17. package/dist/content-handlers/json-handler.js +116 -0
  18. package/dist/content-handlers/json-handler.js.map +1 -0
  19. package/dist/content-handlers/pdf-handler.d.ts +29 -0
  20. package/dist/content-handlers/pdf-handler.d.ts.map +1 -0
  21. package/dist/content-handlers/pdf-handler.js +77 -0
  22. package/dist/content-handlers/pdf-handler.js.map +1 -0
  23. package/dist/content-handlers/svg-handler.d.ts +35 -0
  24. package/dist/content-handlers/svg-handler.d.ts.map +1 -0
  25. package/dist/content-handlers/svg-handler.js +206 -0
  26. package/dist/content-handlers/svg-handler.js.map +1 -0
  27. package/dist/content-handlers/types.d.ts +42 -0
  28. package/dist/content-handlers/types.d.ts.map +1 -0
  29. package/dist/content-handlers/types.js +7 -0
  30. package/dist/content-handlers/types.js.map +1 -0
  31. package/dist/sanitizer/framework-mapper.d.ts +4 -0
  32. package/dist/sanitizer/framework-mapper.d.ts.map +1 -1
  33. package/dist/sanitizer/framework-mapper.js +92 -0
  34. package/dist/sanitizer/framework-mapper.js.map +1 -1
  35. package/dist/sanitizer/threat-reporter.d.ts +5 -0
  36. package/dist/sanitizer/threat-reporter.d.ts.map +1 -1
  37. package/dist/sanitizer/threat-reporter.js +15 -6
  38. package/dist/sanitizer/threat-reporter.js.map +1 -1
  39. package/dist/tools/fetch-structured.d.ts.map +1 -1
  40. package/dist/tools/fetch-structured.js +4 -0
  41. package/dist/tools/fetch-structured.js.map +1 -1
  42. package/dist/tools/fetch.d.ts.map +1 -1
  43. package/dist/tools/fetch.js +68 -4
  44. package/dist/tools/fetch.js.map +1 -1
  45. package/dist/tools/read.d.ts.map +1 -1
  46. package/dist/tools/read.js +4 -0
  47. package/dist/tools/read.js.map +1 -1
  48. package/dist/types.d.ts +9 -1
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/types.js.map +1 -1
  51. package/package.json +2 -1
  52. package/server.json +25 -14
  53. package/src/browser/playwright-renderer.ts +29 -6
  54. package/src/content-handlers/index.ts +72 -0
  55. package/src/content-handlers/json-handler.ts +137 -0
  56. package/src/content-handlers/pdf-handler.ts +91 -0
  57. package/src/content-handlers/svg-handler.ts +243 -0
  58. package/src/content-handlers/types.ts +44 -0
  59. package/src/sanitizer/framework-mapper.ts +94 -0
  60. package/src/sanitizer/threat-reporter.ts +17 -6
  61. package/src/tools/fetch-structured.ts +5 -0
  62. package/src/tools/fetch.ts +76 -4
  63. package/src/tools/read.ts +5 -0
  64. package/src/types.ts +9 -1
  65. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -47
  66. package/.github/ISSUE_TEMPLATE/false_positive.md +0 -43
  67. package/.github/ISSUE_TEMPLATE/new_pattern.md +0 -49
  68. package/.github/ISSUE_TEMPLATE/security_report.md +0 -31
  69. package/.github/PULL_REQUEST_TEMPLATE.md +0 -39
  70. package/.mcpregistry_github_token +0 -1
  71. package/.mcpregistry_registry_token +0 -1
  72. package/CONTRIBUTING.md +0 -329
  73. package/LINKEDIN-STRATEGY.md +0 -367
  74. package/ROADMAP.md +0 -221
  75. package/SECURITY-AUDIT-v1.md +0 -277
  76. package/SUBMISSION.md +0 -66
  77. package/TROUBLESHOOT-AUTH-20260322-2019.md +0 -291
  78. package/TROUBLESHOOT-BUILD-20260319-1450.md +0 -546
  79. package/TROUBLESHOOT-COGNITO-AUTH-20260324-2029.md +0 -415
  80. package/TROUBLESHOOT-COGNITO-JWT-20260324.md +0 -592
  81. package/TROUBLESHOOT-FETCH-20260320-1150.md +0 -168
  82. package/TROUBLESHOOT-JEST-20260323-1357.md +0 -139
  83. package/TROUBLESHOOT-LAMBDA-20260322-1945.md +0 -183
  84. package/TROUBLESHOOT-PLAYWRIGHT-20260321-1549.md +0 -217
  85. package/TROUBLESHOOT-SSL-20260320-1138.md +0 -171
  86. package/TROUBLESHOOT-STRUCTURED-20260320-1200.md +0 -246
  87. package/TROUBLESHOOT-TEST-20260320-0942.md +0 -281
  88. package/VISUS-CLAUDE-CODE-PROMPT.md +0 -324
  89. package/VISUS-PROJECT-PLAN.md +0 -205
  90. package/cdk.json +0 -73
  91. package/infrastructure/app.ts +0 -39
  92. package/infrastructure/stack.ts +0 -298
  93. package/jest.config.js +0 -33
  94. package/jest.setup.js +0 -9
  95. package/lambda-deploy/index.js +0 -81512
  96. package/lambda-deploy/index.js.map +0 -7
  97. package/lambda-package/browser/__mocks__/playwright-renderer.d.ts +0 -25
  98. package/lambda-package/browser/__mocks__/playwright-renderer.d.ts.map +0 -1
  99. package/lambda-package/browser/__mocks__/playwright-renderer.js +0 -119
  100. package/lambda-package/browser/__mocks__/playwright-renderer.js.map +0 -1
  101. package/lambda-package/browser/playwright-renderer.d.ts +0 -40
  102. package/lambda-package/browser/playwright-renderer.d.ts.map +0 -1
  103. package/lambda-package/browser/playwright-renderer.js +0 -214
  104. package/lambda-package/browser/playwright-renderer.js.map +0 -1
  105. package/lambda-package/browser/reader.d.ts +0 -31
  106. package/lambda-package/browser/reader.d.ts.map +0 -1
  107. package/lambda-package/browser/reader.js +0 -98
  108. package/lambda-package/browser/reader.js.map +0 -1
  109. package/lambda-package/index.d.ts +0 -18
  110. package/lambda-package/index.d.ts.map +0 -1
  111. package/lambda-package/index.js +0 -238
  112. package/lambda-package/index.js.map +0 -1
  113. package/lambda-package/lambda-handler.d.ts +0 -28
  114. package/lambda-package/lambda-handler.d.ts.map +0 -1
  115. package/lambda-package/lambda-handler.js +0 -257
  116. package/lambda-package/lambda-handler.js.map +0 -1
  117. package/lambda-package/package-lock.json +0 -7435
  118. package/lambda-package/package.json +0 -74
  119. package/lambda-package/runtime.d.ts +0 -50
  120. package/lambda-package/runtime.d.ts.map +0 -1
  121. package/lambda-package/runtime.js +0 -86
  122. package/lambda-package/runtime.js.map +0 -1
  123. package/lambda-package/sanitizer/elicit-runner.d.ts +0 -48
  124. package/lambda-package/sanitizer/elicit-runner.d.ts.map +0 -1
  125. package/lambda-package/sanitizer/elicit-runner.js +0 -100
  126. package/lambda-package/sanitizer/elicit-runner.js.map +0 -1
  127. package/lambda-package/sanitizer/framework-mapper.d.ts +0 -24
  128. package/lambda-package/sanitizer/framework-mapper.d.ts.map +0 -1
  129. package/lambda-package/sanitizer/framework-mapper.js +0 -342
  130. package/lambda-package/sanitizer/framework-mapper.js.map +0 -1
  131. package/lambda-package/sanitizer/hitl-gate.d.ts +0 -69
  132. package/lambda-package/sanitizer/hitl-gate.d.ts.map +0 -1
  133. package/lambda-package/sanitizer/hitl-gate.js +0 -101
  134. package/lambda-package/sanitizer/hitl-gate.js.map +0 -1
  135. package/lambda-package/sanitizer/index.d.ts +0 -63
  136. package/lambda-package/sanitizer/index.d.ts.map +0 -1
  137. package/lambda-package/sanitizer/index.js +0 -105
  138. package/lambda-package/sanitizer/index.js.map +0 -1
  139. package/lambda-package/sanitizer/injection-detector.d.ts +0 -34
  140. package/lambda-package/sanitizer/injection-detector.d.ts.map +0 -1
  141. package/lambda-package/sanitizer/injection-detector.js +0 -89
  142. package/lambda-package/sanitizer/injection-detector.js.map +0 -1
  143. package/lambda-package/sanitizer/patterns.d.ts +0 -30
  144. package/lambda-package/sanitizer/patterns.d.ts.map +0 -1
  145. package/lambda-package/sanitizer/patterns.js +0 -372
  146. package/lambda-package/sanitizer/patterns.js.map +0 -1
  147. package/lambda-package/sanitizer/pii-allowlist.d.ts +0 -49
  148. package/lambda-package/sanitizer/pii-allowlist.d.ts.map +0 -1
  149. package/lambda-package/sanitizer/pii-allowlist.js +0 -231
  150. package/lambda-package/sanitizer/pii-allowlist.js.map +0 -1
  151. package/lambda-package/sanitizer/pii-redactor.d.ts +0 -41
  152. package/lambda-package/sanitizer/pii-redactor.d.ts.map +0 -1
  153. package/lambda-package/sanitizer/pii-redactor.js +0 -213
  154. package/lambda-package/sanitizer/pii-redactor.js.map +0 -1
  155. package/lambda-package/sanitizer/severity-classifier.d.ts +0 -33
  156. package/lambda-package/sanitizer/severity-classifier.d.ts.map +0 -1
  157. package/lambda-package/sanitizer/severity-classifier.js +0 -113
  158. package/lambda-package/sanitizer/severity-classifier.js.map +0 -1
  159. package/lambda-package/sanitizer/threat-reporter.d.ts +0 -66
  160. package/lambda-package/sanitizer/threat-reporter.d.ts.map +0 -1
  161. package/lambda-package/sanitizer/threat-reporter.js +0 -163
  162. package/lambda-package/sanitizer/threat-reporter.js.map +0 -1
  163. package/lambda-package/tools/fetch-structured.d.ts +0 -51
  164. package/lambda-package/tools/fetch-structured.d.ts.map +0 -1
  165. package/lambda-package/tools/fetch-structured.js +0 -237
  166. package/lambda-package/tools/fetch-structured.js.map +0 -1
  167. package/lambda-package/tools/fetch.d.ts +0 -49
  168. package/lambda-package/tools/fetch.d.ts.map +0 -1
  169. package/lambda-package/tools/fetch.js +0 -131
  170. package/lambda-package/tools/fetch.js.map +0 -1
  171. package/lambda-package/tools/read.d.ts +0 -51
  172. package/lambda-package/tools/read.d.ts.map +0 -1
  173. package/lambda-package/tools/read.js +0 -127
  174. package/lambda-package/tools/read.js.map +0 -1
  175. package/lambda-package/tools/search.d.ts +0 -45
  176. package/lambda-package/tools/search.d.ts.map +0 -1
  177. package/lambda-package/tools/search.js +0 -220
  178. package/lambda-package/tools/search.js.map +0 -1
  179. package/lambda-package/types.d.ts +0 -167
  180. package/lambda-package/types.d.ts.map +0 -1
  181. package/lambda-package/types.js +0 -16
  182. package/lambda-package/types.js.map +0 -1
  183. package/lambda-package/utils/format-converter.d.ts +0 -39
  184. package/lambda-package/utils/format-converter.d.ts.map +0 -1
  185. package/lambda-package/utils/format-converter.js +0 -191
  186. package/lambda-package/utils/format-converter.js.map +0 -1
  187. package/lambda-package/utils/truncate.d.ts +0 -26
  188. package/lambda-package/utils/truncate.d.ts.map +0 -1
  189. package/lambda-package/utils/truncate.js +0 -54
  190. package/lambda-package/utils/truncate.js.map +0 -1
  191. package/lambda.zip +0 -0
  192. package/test-output.txt +0 -4
  193. package/tests/auth-smoke.test.ts +0 -480
  194. package/tests/elicit-runner.test.ts +0 -232
  195. package/tests/fetch-tool.test.ts +0 -922
  196. package/tests/hitl-gate.test.ts +0 -267
  197. package/tests/injection-corpus.ts +0 -338
  198. package/tests/pii-allowlist.test.ts +0 -282
  199. package/tests/reader.test.ts +0 -353
  200. package/tests/sanitizer.test.ts +0 -358
  201. package/tests/search.test.ts +0 -456
  202. package/tests/threat-reporter.test.ts +0 -334
  203. package/tsconfig.cdk.json +0 -35
@@ -1,113 +0,0 @@
1
- /**
2
- * Severity Classification Engine
3
- *
4
- * Maps injection pattern categories to standardized severity levels.
5
- * Used for threat reporting and compliance documentation.
6
- */
7
- /**
8
- * Pattern category to severity mapping
9
- * Aligned with NIST AI 600-1 and OWASP LLM Top 10 risk levels
10
- */
11
- const SEVERITY_MAP = {
12
- // CRITICAL - Immediate threat, block-level
13
- direct_instruction_injection: 'CRITICAL',
14
- role_hijacking: 'CRITICAL',
15
- system_prompt_extraction: 'CRITICAL',
16
- privilege_escalation: 'CRITICAL',
17
- data_exfiltration: 'CRITICAL',
18
- code_execution_requests: 'CRITICAL',
19
- memory_manipulation: 'CRITICAL',
20
- jailbreak_keywords: 'CRITICAL',
21
- ethical_override: 'CRITICAL',
22
- credential_harvesting: 'CRITICAL',
23
- html_script_injection: 'CRITICAL',
24
- // HIGH - Significant threat
25
- context_poisoning: 'HIGH',
26
- base64_obfuscation: 'HIGH',
27
- zero_width_characters: 'HIGH',
28
- data_uri_injection: 'HIGH',
29
- markdown_link_injection: 'HIGH',
30
- instruction_delimiter_injection: 'HIGH',
31
- token_smuggling: 'HIGH',
32
- system_message_injection: 'HIGH',
33
- file_system_access: 'HIGH',
34
- training_data_extraction: 'HIGH',
35
- nested_encoding: 'HIGH',
36
- authority_impersonation: 'HIGH',
37
- callback_url_injection: 'HIGH',
38
- // MEDIUM - Moderate threat
39
- comment_injection: 'MEDIUM',
40
- unicode_lookalikes: 'MEDIUM',
41
- url_fragment_hashjack: 'MEDIUM',
42
- social_engineering_urgency: 'MEDIUM',
43
- multi_language_obfuscation: 'MEDIUM',
44
- reverse_text_obfuscation: 'MEDIUM',
45
- conversation_reset: 'MEDIUM',
46
- chain_of_thought_manipulation: 'MEDIUM',
47
- hypothetical_scenario_injection: 'MEDIUM',
48
- output_format_manipulation: 'MEDIUM',
49
- simulator_mode: 'MEDIUM',
50
- payload_splitting: 'MEDIUM',
51
- css_hiding: 'MEDIUM',
52
- testing_debugging_claims: 'MEDIUM',
53
- // LOW - Low threat, flagged for awareness
54
- leetspeak_obfuscation: 'LOW',
55
- capability_probing: 'LOW',
56
- negative_instruction: 'LOW',
57
- time_based_triggers: 'LOW',
58
- whitespace_steganography: 'LOW'
59
- };
60
- /**
61
- * Classify severity for a single pattern category
62
- */
63
- export function classifySeverity(patternCategory) {
64
- return SEVERITY_MAP[patternCategory] || 'LOW';
65
- }
66
- /**
67
- * Aggregate severity across multiple findings
68
- * Returns the highest severity level found, or CLEAN if no findings
69
- */
70
- export function aggregateSeverity(findings) {
71
- if (findings.length === 0) {
72
- return 'CLEAN';
73
- }
74
- const severities = findings.map(f => f.severity);
75
- if (severities.includes('CRITICAL'))
76
- return 'CRITICAL';
77
- if (severities.includes('HIGH'))
78
- return 'HIGH';
79
- if (severities.includes('MEDIUM'))
80
- return 'MEDIUM';
81
- if (severities.includes('LOW'))
82
- return 'LOW';
83
- return 'CLEAN';
84
- }
85
- /**
86
- * Count findings by severity level
87
- */
88
- export function countBySeverity(findings) {
89
- const counts = {
90
- CRITICAL: 0,
91
- HIGH: 0,
92
- MEDIUM: 0,
93
- LOW: 0
94
- };
95
- for (const finding of findings) {
96
- counts[finding.severity]++;
97
- }
98
- return counts;
99
- }
100
- /**
101
- * Get emoji for severity level (for Markdown reports)
102
- */
103
- export function getSeverityEmoji(severity) {
104
- switch (severity) {
105
- case 'CRITICAL': return '🔴';
106
- case 'HIGH': return '🟠';
107
- case 'MEDIUM': return '🟡';
108
- case 'LOW': return '🟢';
109
- case 'CLEAN': return '✅';
110
- default: return '⚪';
111
- }
112
- }
113
- //# sourceMappingURL=severity-classifier.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"severity-classifier.js","sourceRoot":"","sources":["../../src/sanitizer/severity-classifier.ts"],"names":[],"mappings":"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"}
@@ -1,66 +0,0 @@
1
- /**
2
- * Threat Reporter
3
- *
4
- * Generates structured threat reports when prompt injection or PII is detected.
5
- * Two output layers:
6
- * 1. TOON-formatted findings array (token-efficient, machine-readable)
7
- * 2. Markdown compliance report block (human-readable, renders in Claude Desktop)
8
- *
9
- * Aligned with:
10
- * - OWASP LLM Top 10 (2025)
11
- * - NIST AI 600-1 (Generative AI Profile)
12
- * - MITRE ATLAS (Adversarial Threat Landscape)
13
- */
14
- import { type Severity, type OverallSeverity } from './severity-classifier.js';
15
- /**
16
- * Threat finding with compliance framework mappings
17
- */
18
- export interface ThreatFinding {
19
- id: number;
20
- pattern_id: string;
21
- category: string;
22
- severity: Severity;
23
- confidence: number;
24
- owasp_llm: string;
25
- nist_ai_600_1: string;
26
- mitre_atlas: string;
27
- iso_42001: string;
28
- remediation: string;
29
- }
30
- /**
31
- * Threat report structure
32
- */
33
- export interface ThreatReport {
34
- generated: string;
35
- source_url: string;
36
- overall_severity: OverallSeverity;
37
- total_findings: number;
38
- by_severity: Record<Severity, number>;
39
- pii_redacted: number;
40
- sanitization_applied: boolean;
41
- frameworks: string[];
42
- findings_toon: string;
43
- report_markdown: string;
44
- }
45
- /**
46
- * Input to threat reporter
47
- */
48
- export interface ThreatReportInput {
49
- patterns_detected: string[];
50
- pii_redacted: number;
51
- source_url: string;
52
- timestamp?: string;
53
- detections_by_severity?: {
54
- critical: number;
55
- high: number;
56
- medium: number;
57
- low: number;
58
- };
59
- }
60
- /**
61
- * Generate threat report (main entry point)
62
- *
63
- * Returns null if no findings (injections_removed === 0 AND pii_redacted === 0)
64
- */
65
- export declare function generateThreatReport(input: ThreatReportInput): ThreatReport | null;
66
- //# sourceMappingURL=threat-reporter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"threat-reporter.d.ts","sourceRoot":"","sources":["../../src/sanitizer/threat-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAKL,KAAK,QAAQ,EACb,KAAK,eAAe,EAErB,MAAM,0BAA0B,CAAC;AAGlC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,eAAe,CAAC;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAsID;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,GAAG,IAAI,CAsDlF"}
@@ -1,163 +0,0 @@
1
- /**
2
- * Threat Reporter
3
- *
4
- * Generates structured threat reports when prompt injection or PII is detected.
5
- * Two output layers:
6
- * 1. TOON-formatted findings array (token-efficient, machine-readable)
7
- * 2. Markdown compliance report block (human-readable, renders in Claude Desktop)
8
- *
9
- * Aligned with:
10
- * - OWASP LLM Top 10 (2025)
11
- * - NIST AI 600-1 (Generative AI Profile)
12
- * - MITRE ATLAS (Adversarial Threat Landscape)
13
- */
14
- import { classifySeverity, aggregateSeverity, countBySeverity, getSeverityEmoji } from './severity-classifier.js';
15
- import { getFrameworkMappings } from './framework-mapper.js';
16
- /**
17
- * Generate pattern ID from category name
18
- * Format: PI-XXX where XXX is a zero-padded number based on hash
19
- */
20
- function generatePatternId(category) {
21
- // Simple hash to generate consistent IDs
22
- let hash = 0;
23
- for (let i = 0; i < category.length; i++) {
24
- hash = ((hash << 5) - hash) + category.charCodeAt(i);
25
- hash = hash & hash;
26
- }
27
- const id = Math.abs(hash) % 1000;
28
- return `PI-${String(id).padStart(3, '0')}`;
29
- }
30
- /**
31
- * Build findings data structure from pattern detections
32
- */
33
- function buildFindings(patternsDetected) {
34
- return patternsDetected.map((category, index) => {
35
- const severity = classifySeverity(category);
36
- const frameworks = getFrameworkMappings(category);
37
- const patternId = generatePatternId(category);
38
- return {
39
- id: index + 1,
40
- pattern_id: patternId,
41
- category,
42
- severity,
43
- confidence: 0.95, // Default confidence; can be enhanced later
44
- owasp_llm: frameworks.owasp_llm,
45
- nist_ai_600_1: frameworks.nist_ai_600_1,
46
- mitre_atlas: frameworks.mitre_atlas,
47
- iso_42001: frameworks.iso_42001,
48
- remediation: `Content sanitized. ${category.replace(/_/g, ' ')} removed.`
49
- };
50
- });
51
- }
52
- /**
53
- * Generate TOON-encoded findings string
54
- * Using manual TOON format to avoid Jest ESM compatibility issues
55
- */
56
- function generateToonFindings(findings) {
57
- if (findings.length === 0) {
58
- return '';
59
- }
60
- return generateManualToonFormat(findings);
61
- }
62
- /**
63
- * Fallback manual TOON format generation
64
- */
65
- function generateManualToonFormat(findings) {
66
- const header = `findings[${findings.length}]{id,pattern_id,category,severity,confidence,owasp_llm,nist_ai_600_1,mitre_atlas,iso_42001,remediation}:`;
67
- const rows = findings.map(f => `${f.id},${f.pattern_id},${f.category},${f.severity},${f.confidence},${f.owasp_llm},${f.nist_ai_600_1},${f.mitre_atlas},${f.iso_42001},${f.remediation}`);
68
- return `${header}\n${rows.join('\n')}`;
69
- }
70
- /**
71
- * Generate Markdown report block
72
- */
73
- function generateMarkdownReport(findings, overallSeverity, bySeverity, piiRedacted, sourceUrl, timestamp) {
74
- const emoji = getSeverityEmoji(overallSeverity);
75
- let markdown = '---\n';
76
- markdown += `## ${emoji} Visus Threat Report\n`;
77
- markdown += `**Generated:** ${timestamp}\n`;
78
- markdown += `**Source:** ${sourceUrl}\n`;
79
- markdown += `**Overall Severity:** ${overallSeverity}\n`;
80
- markdown += `**Framework:** OWASP LLM Top 10 | NIST AI 600-1 | MITRE ATLAS | ISO/IEC 42001\n\n`;
81
- // Findings Summary
82
- markdown += '### Findings Summary\n';
83
- markdown += '| Severity | Count |\n';
84
- markdown += '|---|---|\n';
85
- markdown += `| ${getSeverityEmoji('CRITICAL')} CRITICAL | ${bySeverity.CRITICAL} |\n`;
86
- markdown += `| ${getSeverityEmoji('HIGH')} HIGH | ${bySeverity.HIGH} |\n`;
87
- markdown += `| ${getSeverityEmoji('MEDIUM')} MEDIUM | ${bySeverity.MEDIUM} |\n`;
88
- markdown += `| ${getSeverityEmoji('LOW')} LOW | ${bySeverity.LOW} |\n\n`;
89
- // Findings Detail (only if we have findings)
90
- if (findings.length > 0) {
91
- markdown += '### Findings Detail\n';
92
- markdown += '| # | Category | Severity | Confidence | OWASP | MITRE | ISO 42001 |\n';
93
- markdown += '|---|---|---|---|---|---|---|\n';
94
- for (const finding of findings.slice(0, 10)) { // Limit to first 10 for readability
95
- const confidencePct = Math.round(finding.confidence * 100);
96
- const owaspShort = finding.owasp_llm.split(' - ')[0]; // e.g., "LLM01:2025"
97
- const mitreShort = finding.mitre_atlas.split(' - ')[0]; // e.g., "AML.T0051.000"
98
- const isoShort = finding.iso_42001.split(' - ')[0]; // e.g., "A.6.1.5"
99
- markdown += `| ${finding.id} | ${finding.category} | ${finding.severity} | ${confidencePct}% | ${owaspShort} | ${mitreShort} | ${isoShort} |\n`;
100
- }
101
- if (findings.length > 10) {
102
- markdown += `\n*...and ${findings.length - 10} more findings*\n`;
103
- }
104
- markdown += '\n';
105
- }
106
- // PII Redaction
107
- if (piiRedacted > 0) {
108
- markdown += '### PII Redaction\n';
109
- markdown += `- **Items Redacted:** ${piiRedacted}\n`;
110
- markdown += `- **Standard:** NIST AI 600-1 MS-2.6\n\n`;
111
- }
112
- // Remediation Status
113
- markdown += '### Remediation Status\n';
114
- markdown += '✅ All findings sanitized. Content delivered clean.\n\n';
115
- // TODO: PDF export hook for future visus_report tool
116
- // This is where the PDF generation would be triggered in Phase 3
117
- markdown += '*Report generated by Visus MCP — Security-first web access for Claude*\n';
118
- markdown += '---\n';
119
- return markdown;
120
- }
121
- /**
122
- * Generate threat report (main entry point)
123
- *
124
- * Returns null if no findings (injections_removed === 0 AND pii_redacted === 0)
125
- */
126
- export function generateThreatReport(input) {
127
- const { patterns_detected, pii_redacted, source_url, timestamp = new Date().toISOString() } = input;
128
- // Omit threat report if nothing was found
129
- if (patterns_detected.length === 0 && pii_redacted === 0) {
130
- return null;
131
- }
132
- // Build findings from detected patterns
133
- const findings = buildFindings(patterns_detected);
134
- // Calculate severity
135
- const severityFindings = findings.map(f => ({
136
- pattern_category: f.category,
137
- severity: f.severity
138
- }));
139
- const overallSeverity = aggregateSeverity(severityFindings);
140
- const bySeverity = countBySeverity(severityFindings);
141
- // Generate TOON findings
142
- const toonFindings = generateToonFindings(findings);
143
- // Generate Markdown report
144
- const markdownReport = generateMarkdownReport(findings, overallSeverity, bySeverity, pii_redacted, source_url, timestamp);
145
- return {
146
- generated: timestamp,
147
- source_url,
148
- overall_severity: overallSeverity,
149
- total_findings: findings.length,
150
- by_severity: bySeverity,
151
- pii_redacted,
152
- sanitization_applied: true,
153
- frameworks: [
154
- 'OWASP LLM Top 10',
155
- 'NIST AI 600-1',
156
- 'MITRE ATLAS',
157
- 'ISO/IEC 42001'
158
- ],
159
- findings_toon: toonFindings,
160
- report_markdown: markdownReport
161
- };
162
- }
163
- //# sourceMappingURL=threat-reporter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"threat-reporter.js","sourceRoot":"","sources":["../../src/sanitizer/threat-reporter.ts"],"names":[],"mappings":"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"}
@@ -1,51 +0,0 @@
1
- /**
2
- * visus_fetch_structured MCP Tool
3
- *
4
- * Fetches a web page and extracts structured data according to a schema.
5
- * All extracted data is sanitized before being returned.
6
- *
7
- * CRITICAL: ALL content MUST pass through the sanitizer. This cannot be bypassed.
8
- */
9
- import type { VisusFetchStructuredInput, VisusFetchStructuredOutput, Result } from '../types.js';
10
- /**
11
- * visus_fetch_structured tool implementation
12
- *
13
- * @param input Tool input parameters
14
- * @returns Extracted and sanitized structured data
15
- */
16
- export declare function visusFetchStructured(input: VisusFetchStructuredInput): Promise<Result<VisusFetchStructuredOutput, Error>>;
17
- /**
18
- * MCP tool definition for registration
19
- */
20
- export declare const visusFetchStructuredToolDefinition: {
21
- name: string;
22
- title: string;
23
- description: string;
24
- inputSchema: {
25
- type: string;
26
- properties: {
27
- url: {
28
- type: string;
29
- description: string;
30
- };
31
- schema: {
32
- type: string;
33
- description: string;
34
- additionalProperties: {
35
- type: string;
36
- };
37
- };
38
- timeout_ms: {
39
- type: string;
40
- description: string;
41
- default: number;
42
- };
43
- };
44
- required: string[];
45
- };
46
- readOnlyHint: boolean;
47
- destructiveHint: boolean;
48
- idempotentHint: boolean;
49
- openWorldHint: boolean;
50
- };
51
- //# sourceMappingURL=fetch-structured.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetch-structured.d.ts","sourceRoot":"","sources":["../../src/tools/fetch-structured.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AA2EjG;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,MAAM,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC,CA4IpD;AAED;;GAEG;AACH,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8B9C,CAAC"}
@@ -1,237 +0,0 @@
1
- /**
2
- * visus_fetch_structured MCP Tool
3
- *
4
- * Fetches a web page and extracts structured data according to a schema.
5
- * All extracted data is sanitized before being returned.
6
- *
7
- * CRITICAL: ALL content MUST pass through the sanitizer. This cannot be bypassed.
8
- */
9
- import * as cheerio from 'cheerio';
10
- import { renderPage } from '../browser/playwright-renderer.js';
11
- import { sanitize } from '../sanitizer/index.js';
12
- import { truncateContent } from '../utils/truncate.js';
13
- import { generateThreatReport } from '../sanitizer/threat-reporter.js';
14
- import { Err } from '../types.js';
15
- /**
16
- * Extract structured data from HTML using cheerio
17
- *
18
- * Phase 1: cheerio-based semantic HTML extraction
19
- * Phase 2+: LLM-powered extraction with Bedrock for complex schemas
20
- */
21
- function extractStructuredData(html, schema) {
22
- const $ = cheerio.load(html);
23
- const extracted = {};
24
- for (const [fieldName, description] of Object.entries(schema)) {
25
- const descLower = description.toLowerCase();
26
- let value = null;
27
- // Pattern: main heading, title, h1
28
- if (descLower.includes('heading') || descLower.includes('title') || descLower.includes('h1')) {
29
- const h1 = $('h1').first().text().trim();
30
- if (h1)
31
- value = h1;
32
- }
33
- // Pattern: subheading, subtitle, h2, h3
34
- else if (descLower.includes('subheading') || descLower.includes('subtitle') || descLower.includes('h2') || descLower.includes('h3')) {
35
- const h2 = $('h2, h3').first().text().trim();
36
- if (h2)
37
- value = h2;
38
- }
39
- // Pattern: paragraph, body text, description
40
- else if (descLower.includes('paragraph') || descLower.includes('body') || descLower.includes('description')) {
41
- const p = $('p').first().text().trim();
42
- if (p)
43
- value = p;
44
- }
45
- // Pattern: link, url, href
46
- else if (descLower.includes('link') || descLower.includes('url') || descLower.includes('href')) {
47
- const link = $('a').first();
48
- const href = link.attr('href');
49
- if (href)
50
- value = href;
51
- }
52
- // Pattern: link text, anchor text
53
- else if (descLower.includes('link text') || descLower.includes('anchor')) {
54
- const linkText = $('a').first().text().trim();
55
- if (linkText)
56
- value = linkText;
57
- }
58
- // Pattern: page title (from <title> tag)
59
- else if (descLower.includes('page title') || descLower.includes('document title')) {
60
- const title = $('title').text().trim();
61
- if (title)
62
- value = title;
63
- }
64
- // Fallback: try to find text containing the field name
65
- else {
66
- const elements = $('*').filter((_, el) => {
67
- const text = $(el).text().toLowerCase();
68
- return text.includes(fieldName.toLowerCase()) || text.includes(descLower);
69
- });
70
- if (elements.length > 0) {
71
- value = $(elements.first()).text().trim();
72
- }
73
- }
74
- extracted[fieldName] = value;
75
- }
76
- return extracted;
77
- }
78
- /**
79
- * visus_fetch_structured tool implementation
80
- *
81
- * @param input Tool input parameters
82
- * @returns Extracted and sanitized structured data
83
- */
84
- export async function visusFetchStructured(input) {
85
- const { url, schema, timeout_ms = 10000 } = input;
86
- // Validate inputs
87
- if (!url || typeof url !== 'string') {
88
- return Err(new Error('Invalid input: url must be a non-empty string'));
89
- }
90
- if (!schema || typeof schema !== 'object' || Object.keys(schema).length === 0) {
91
- return Err(new Error('Invalid input: schema must be a non-empty object'));
92
- }
93
- try {
94
- // Step 1: Render the page (use default format to get HTML)
95
- const renderResult = await renderPage(url, {
96
- timeout_ms
97
- });
98
- if (!renderResult.ok) {
99
- return Err(renderResult.error);
100
- }
101
- const { title, html } = renderResult.value;
102
- // Step 2: Extract structured data from HTML using cheerio
103
- const extractedData = extractStructuredData(html, schema);
104
- // Step 3: CRITICAL - Sanitize each extracted field (with allowlisting)
105
- // This step CANNOT be skipped or bypassed
106
- const sanitizedData = {};
107
- const allPatternsDetected = new Set();
108
- const allPIITypesRedacted = new Set();
109
- const allPIIAllowlisted = [];
110
- let anyContentModified = false;
111
- for (const [fieldName, value] of Object.entries(extractedData)) {
112
- if (value === null) {
113
- sanitizedData[fieldName] = null;
114
- continue;
115
- }
116
- const sanitizationResult = sanitize(value, url);
117
- sanitizedData[fieldName] = sanitizationResult.content;
118
- // Collect all patterns detected across fields
119
- sanitizationResult.sanitization.patterns_detected.forEach(p => allPatternsDetected.add(p));
120
- sanitizationResult.sanitization.pii_types_redacted.forEach(p => allPIITypesRedacted.add(p));
121
- allPIIAllowlisted.push(...sanitizationResult.sanitization.pii_allowlisted);
122
- if (sanitizationResult.sanitization.content_modified) {
123
- anyContentModified = true;
124
- }
125
- }
126
- // Step 4: Apply token ceiling truncation to combined data (AFTER sanitization)
127
- // Combine all field values to check total content size
128
- const combinedData = Object.entries(sanitizedData)
129
- .map(([key, value]) => `${key}: ${value || 'null'}`)
130
- .join('\n');
131
- const truncationResult = truncateContent(combinedData);
132
- // If truncated, we need to reconstruct sanitizedData from truncated content
133
- let finalData = sanitizedData;
134
- if (truncationResult.truncated) {
135
- // Parse truncated content back into fields
136
- // This is a simple approach - in production you might want more sophisticated handling
137
- const lines = truncationResult.content.split('\n');
138
- finalData = {};
139
- for (const line of lines) {
140
- if (line.includes(':')) {
141
- const [key, ...valueParts] = line.split(':');
142
- const value = valueParts.join(':').trim();
143
- if (key.trim() in sanitizedData) {
144
- finalData[key.trim()] = value === 'null' ? null : value;
145
- }
146
- }
147
- }
148
- // Preserve any missing fields as null
149
- for (const key of Object.keys(sanitizedData)) {
150
- if (!(key in finalData)) {
151
- finalData[key] = null;
152
- }
153
- }
154
- }
155
- // Step 5: Generate aggregated threat report
156
- const threatReport = generateThreatReport({
157
- patterns_detected: Array.from(allPatternsDetected),
158
- pii_redacted: Array.from(allPIITypesRedacted).length,
159
- source_url: url
160
- });
161
- // Step 6: Build output
162
- const output = {
163
- url,
164
- data: finalData,
165
- sanitization: {
166
- patterns_detected: Array.from(allPatternsDetected),
167
- pii_types_redacted: Array.from(allPIITypesRedacted),
168
- pii_allowlisted: allPIIAllowlisted,
169
- content_modified: anyContentModified
170
- },
171
- metadata: {
172
- title: title || 'Untitled',
173
- fetched_at: new Date().toISOString(),
174
- content_length_original: html.length,
175
- content_length_sanitized: Object.values(sanitizedData)
176
- .filter(v => v !== null)
177
- .join(' ')
178
- .length,
179
- ...(truncationResult.truncated && {
180
- truncated: true,
181
- truncated_at_chars: truncationResult.truncated_at_chars
182
- })
183
- },
184
- // Include threat_report only if findings exist
185
- ...(threatReport && { threat_report: threatReport })
186
- };
187
- // Log to stderr if threats detected
188
- if (allPatternsDetected.size > 0) {
189
- console.error(JSON.stringify({
190
- timestamp: new Date().toISOString(),
191
- event: 'structured_extraction_threats',
192
- url,
193
- patterns: Array.from(allPatternsDetected),
194
- fields: Object.keys(schema)
195
- }));
196
- }
197
- return { ok: true, value: output };
198
- }
199
- catch (error) {
200
- return Err(error instanceof Error ? error : new Error(String(error)));
201
- }
202
- }
203
- /**
204
- * MCP tool definition for registration
205
- */
206
- export const visusFetchStructuredToolDefinition = {
207
- name: 'visus_fetch_structured',
208
- title: 'Fetch Structured Data (Sanitized)',
209
- description: 'Fetch a web page and extract structured data according to a schema. SECURITY: All extracted fields pass through prompt injection sanitization (43 pattern categories) and PII redaction BEFORE being returned to the LLM. Each field is independently sanitized to ensure safe consumption of untrusted web content.',
210
- inputSchema: {
211
- type: 'object',
212
- properties: {
213
- url: {
214
- type: 'string',
215
- description: 'The URL to fetch (must be http:// or https://)'
216
- },
217
- schema: {
218
- type: 'object',
219
- description: 'Field extraction schema: { fieldName: "field description", ... }',
220
- additionalProperties: {
221
- type: 'string'
222
- }
223
- },
224
- timeout_ms: {
225
- type: 'number',
226
- description: 'Request timeout in milliseconds (default: 10000)',
227
- default: 10000
228
- }
229
- },
230
- required: ['url', 'schema']
231
- },
232
- readOnlyHint: true,
233
- destructiveHint: false,
234
- idempotentHint: true,
235
- openWorldHint: true
236
- };
237
- //# sourceMappingURL=fetch-structured.js.map