vigile-scan 2.1.0 → 3.0.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.
- package/README.md +6 -5
- package/dist/index.js +62 -5
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
npx vigile-scan
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
That's it. No install, no config. Vigile discovers your MCP server configurations and agent skill files, scans them against
|
|
14
|
+
That's it. No install, no config. Vigile discovers your MCP server configurations and agent skill files, scans them against 59 detection rules, and gives you a trust score for each one.
|
|
15
15
|
|
|
16
16
|
## What It Detects
|
|
17
17
|
|
|
@@ -25,7 +25,7 @@ That's it. No install, no config. Vigile discovers your MCP server configuration
|
|
|
25
25
|
| OB-001–004 | Obfuscation | Base64 content, zero-width Unicode, hex-encoded strings, Unicode escapes |
|
|
26
26
|
| EV/AR/CM | Inline Checks | Sensitive env vars, security bypass flags, sensitive directory args, auto-install (npx -y), typosquatting |
|
|
27
27
|
|
|
28
|
-
### Agent Skill Threats (
|
|
28
|
+
### Agent Skill Threats (32 patterns)
|
|
29
29
|
|
|
30
30
|
| ID | Category | What It Catches |
|
|
31
31
|
|----|----------|-----------------|
|
|
@@ -35,6 +35,7 @@ That's it. No install, no config. Vigile discovers your MCP server configuration
|
|
|
35
35
|
| SK-030–033 | Safety Bypass | Confirmation bypass, safety feature disable, force flags, root/sudo escalation |
|
|
36
36
|
| SK-040–043 | Persistence Abuse | Startup file modification, memory file tampering, cron jobs, git hook injection |
|
|
37
37
|
| SK-050–053 | Data Exfiltration | Credential harvesting, URL-based exfiltration, filesystem enumeration, env var dumping |
|
|
38
|
+
| SK-060–064 | Location Guard | GPS spoofing, location-aware triggers, geo-targeting attacks, location-based access control bypass |
|
|
38
39
|
|
|
39
40
|
## Platforms
|
|
40
41
|
|
|
@@ -160,15 +161,15 @@ When you run `--sentinel`, Vigile intercepts outbound network traffic from your
|
|
|
160
161
|
- **DNS tunneling** — data exfiltration hidden in DNS queries
|
|
161
162
|
- **Unexpected destinations** — connections to IPs/domains outside the expected set
|
|
162
163
|
|
|
163
|
-
Sentinel is available on Pro ($
|
|
164
|
+
Sentinel is available on Pro ($30/mo) and Pro+ ($100/mo) plans. Free users can run static scans with no limits.
|
|
164
165
|
|
|
165
166
|
## Pricing
|
|
166
167
|
|
|
167
168
|
| Tier | Price | Highlights |
|
|
168
169
|
|------|-------|------------|
|
|
169
170
|
| Free | $0/forever | Unlimited CLI scans, 50 API scans/month, registry browsing |
|
|
170
|
-
| Pro | $
|
|
171
|
-
| Pro+ | $
|
|
171
|
+
| Pro | $30/mo | Sentinel monitoring (5 min, 3 servers), 1,000 API scans |
|
|
172
|
+
| Pro+ | $100/mo | Sentinel (30 min, 10 servers), DNS tunneling & C2 detection, alerts |
|
|
172
173
|
|
|
173
174
|
## Links
|
|
174
175
|
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "vigile-scan",
|
|
34
|
-
version: "
|
|
34
|
+
version: "3.0.1",
|
|
35
35
|
description: "Security scanner for AI agent tools \u2014 detect tool poisoning, permission abuse, and supply chain attacks in MCP servers and agent skills",
|
|
36
36
|
main: "dist/index.js",
|
|
37
37
|
bin: {
|
|
@@ -52,7 +52,10 @@ var require_package = __commonJS({
|
|
|
52
52
|
test: "vitest run",
|
|
53
53
|
"test:watch": "vitest",
|
|
54
54
|
"test:coverage": "vitest run --coverage",
|
|
55
|
-
|
|
55
|
+
"audit:check": "npm audit --omit=dev --audit-level=moderate",
|
|
56
|
+
"audit:all": "npm audit --audit-level=moderate",
|
|
57
|
+
preversion: "npm run build && npm test && npm run audit:check",
|
|
58
|
+
prepublishOnly: "npm run build && npm test && npm run audit:check"
|
|
56
59
|
},
|
|
57
60
|
keywords: [
|
|
58
61
|
"mcp",
|
|
@@ -94,9 +97,12 @@ var require_package = __commonJS({
|
|
|
94
97
|
ora: "^8.1.0"
|
|
95
98
|
},
|
|
96
99
|
devDependencies: {
|
|
100
|
+
"@eslint/js": "^10.0.1",
|
|
97
101
|
"@types/node": "^20.11.0",
|
|
102
|
+
eslint: "^10.0.3",
|
|
98
103
|
tsup: "^8.0.0",
|
|
99
104
|
typescript: "^5.4.0",
|
|
105
|
+
"typescript-eslint": "^8.56.1",
|
|
100
106
|
vitest: "^2.0.0"
|
|
101
107
|
}
|
|
102
108
|
};
|
|
@@ -720,6 +726,7 @@ var OBFUSCATION_PATTERNS = [
|
|
|
720
726
|
category: "obfuscation",
|
|
721
727
|
severity: "high",
|
|
722
728
|
title: "Zero-width characters detected",
|
|
729
|
+
// eslint-disable-next-line no-misleading-character-class -- intentional: detecting zero-width unicode
|
|
723
730
|
pattern: /[\u200B\u200C\u200D\uFEFF\u2060\u2061\u2062\u2063\u2064]/,
|
|
724
731
|
description: "Tool description contains invisible zero-width Unicode characters that may hide content.",
|
|
725
732
|
recommendation: "Strip zero-width characters and inspect the resulting text."
|
|
@@ -1073,6 +1080,7 @@ var INSTRUCTION_INJECTION_PATTERNS = [
|
|
|
1073
1080
|
category: "instruction-injection",
|
|
1074
1081
|
severity: "medium",
|
|
1075
1082
|
title: "Invisible unicode directives",
|
|
1083
|
+
// eslint-disable-next-line no-misleading-character-class -- intentional: detecting invisible unicode clusters
|
|
1076
1084
|
pattern: /[\u200B\u200C\u200D\uFEFF\u2060-\u2064\u00AD]{3,}/,
|
|
1077
1085
|
description: "Skill file contains clusters of invisible Unicode characters that may hide instructions from visual review.",
|
|
1078
1086
|
recommendation: "Strip invisible characters and inspect the resulting content."
|
|
@@ -1277,13 +1285,61 @@ var SKILL_EXFILTRATION_PATTERNS = [
|
|
|
1277
1285
|
recommendation: "Review why this skill needs access to all environment variables."
|
|
1278
1286
|
}
|
|
1279
1287
|
];
|
|
1288
|
+
var LOCATION_PATTERNS = [
|
|
1289
|
+
{
|
|
1290
|
+
id: "SK-060",
|
|
1291
|
+
category: "location-privacy",
|
|
1292
|
+
severity: "high",
|
|
1293
|
+
title: "Browser geolocation access",
|
|
1294
|
+
pattern: /(?:navigator\s*\.\s*geolocation|getCurrentPosition|watchPosition|GeolocationPosition|geolocation\s*\.\s*(?:get|watch|clear))/i,
|
|
1295
|
+
description: "Skill accesses browser geolocation API, which reveals the user's precise physical location.",
|
|
1296
|
+
recommendation: "Verify this skill genuinely needs location data. Geolocation exposes latitude/longitude \u2014 high privacy risk if exfiltrated."
|
|
1297
|
+
},
|
|
1298
|
+
{
|
|
1299
|
+
id: "SK-061",
|
|
1300
|
+
category: "location-privacy",
|
|
1301
|
+
severity: "high",
|
|
1302
|
+
title: "Mobile/native geolocation library",
|
|
1303
|
+
pattern: /(?:@react-native-community\/geolocation|expo-location|react-native-geolocation|Geolocation\.requestAuthorization|CLLocationManager|LocationManager|FusedLocationProvider|ACCESS_FINE_LOCATION|ACCESS_COARSE_LOCATION|requestLocationPermission)/i,
|
|
1304
|
+
description: "Skill uses a native mobile geolocation library to access device GPS coordinates.",
|
|
1305
|
+
recommendation: "Mobile location APIs provide high-precision GPS data. Ensure this skill has a legitimate need for physical location and does not transmit it externally."
|
|
1306
|
+
},
|
|
1307
|
+
{
|
|
1308
|
+
id: "SK-062",
|
|
1309
|
+
category: "location-privacy",
|
|
1310
|
+
severity: "critical",
|
|
1311
|
+
title: "Location data exfiltration",
|
|
1312
|
+
pattern: /(?:(?:send|post|upload|transmit|exfiltrate|forward|share|log|track|record)\s+(?:the\s+)?(?:user(?:'s)?\s+)?(?:location|coordinates?|gps|lat(?:itude)?|lng|lon(?:gitude)?|geo(?:location)?|position|whereabouts))|(?:(?:location|coordinates?|gps|lat(?:itude)?|lng|lon(?:gitude)?|geo(?:location)?|position)\s+(?:to|via|through|using)\s+(?:https?|api|endpoint|server|webhook|url))/i,
|
|
1313
|
+
description: "Skill instructs the agent to send location data to an external endpoint. This is a location exfiltration pattern.",
|
|
1314
|
+
recommendation: "CRITICAL: Do NOT install. This skill attempts to exfiltrate physical location data \u2014 a severe privacy violation."
|
|
1315
|
+
},
|
|
1316
|
+
{
|
|
1317
|
+
id: "SK-063",
|
|
1318
|
+
category: "location-privacy",
|
|
1319
|
+
severity: "medium",
|
|
1320
|
+
title: "IP-based geolocation lookup",
|
|
1321
|
+
pattern: /(?:ip-api\.com|ipinfo\.io|ipgeolocation|ip2location|geoip|maxmind|freegeoip|geolite|ip\s*(?:to|2)\s*(?:geo|location))|(?:(?:get|fetch|lookup|resolve)\s+(?:the\s+)?(?:user(?:'s)?\s+)?(?:location|city|country|region|timezone)\s+(?:from|via|using)\s+(?:ip|IP))/i,
|
|
1322
|
+
description: "Skill performs IP-based geolocation to approximate the user's physical location without explicit GPS access.",
|
|
1323
|
+
recommendation: "IP geolocation bypasses browser permission prompts. Verify this skill needs approximate location and isn't using it to fingerprint or track users."
|
|
1324
|
+
},
|
|
1325
|
+
{
|
|
1326
|
+
id: "SK-064",
|
|
1327
|
+
category: "location-privacy",
|
|
1328
|
+
severity: "medium",
|
|
1329
|
+
title: "Geofencing or location boundary check",
|
|
1330
|
+
pattern: /(?:geofenc(?:e|ing)|location\s*(?:boundary|fence|perimeter|zone|radius|range)|within\s+(?:\d+\s*)?(?:meters?|miles?|km|kilometers?)\s+of|haversine|vincenty|h3\s*(?:cell|index|resolution|boundary)|(?:enter|exit|cross)(?:ing|ed)?\s+(?:the\s+)?(?:geo)?fence)/i,
|
|
1331
|
+
description: "Skill implements geofencing or location boundary detection, which requires continuous location monitoring.",
|
|
1332
|
+
recommendation: "Geofencing requires persistent location tracking. Review whether the boundary checks are appropriate and data isn't being logged or exfiltrated."
|
|
1333
|
+
}
|
|
1334
|
+
];
|
|
1280
1335
|
var ALL_SKILL_PATTERNS = [
|
|
1281
1336
|
...INSTRUCTION_INJECTION_PATTERNS,
|
|
1282
1337
|
...MALWARE_DELIVERY_PATTERNS,
|
|
1283
1338
|
...STEALTH_PATTERNS,
|
|
1284
1339
|
...SAFETY_BYPASS_PATTERNS,
|
|
1285
1340
|
...PERSISTENCE_PATTERNS,
|
|
1286
|
-
...SKILL_EXFILTRATION_PATTERNS
|
|
1341
|
+
...SKILL_EXFILTRATION_PATTERNS,
|
|
1342
|
+
...LOCATION_PATTERNS
|
|
1287
1343
|
];
|
|
1288
1344
|
|
|
1289
1345
|
// src/scanner/skill-scanner.ts
|
|
@@ -1351,7 +1407,7 @@ function analyzeStructure(skill) {
|
|
|
1351
1407
|
let codeMatch;
|
|
1352
1408
|
while ((codeMatch = codeBlockPattern.exec(content)) !== null) {
|
|
1353
1409
|
const codeBlock = codeMatch[1];
|
|
1354
|
-
if (/rm\s+-rf\s+[
|
|
1410
|
+
if (/rm\s+-rf\s+[/~]|rm\s+-rf\s+\$\{?HOME/.test(codeBlock)) {
|
|
1355
1411
|
findings.push({
|
|
1356
1412
|
id: "SK-061",
|
|
1357
1413
|
category: "permission-abuse",
|
|
@@ -3633,6 +3689,7 @@ var SECRET_PATTERNS = [
|
|
|
3633
3689
|
provider: "cryptographic",
|
|
3634
3690
|
severity: "critical",
|
|
3635
3691
|
pattern: /-----BEGIN PGP PRIVATE KEY BLOCK-----/,
|
|
3692
|
+
// nosemgrep: detected-pgp-private-key-block — this is a detection pattern, not an actual key
|
|
3636
3693
|
description: "PGP/GPG private key embedded in source.",
|
|
3637
3694
|
recommendation: "Remove and revoke the key at your keyserver."
|
|
3638
3695
|
},
|
|
@@ -5165,7 +5222,7 @@ async function runScan(options) {
|
|
|
5165
5222
|
if (options.output) {
|
|
5166
5223
|
await (0, import_promises5.writeFile)(options.output, jsonOutput);
|
|
5167
5224
|
} else {
|
|
5168
|
-
await new Promise((resolve,
|
|
5225
|
+
await new Promise((resolve, _reject) => {
|
|
5169
5226
|
const ok = process.stdout.write(jsonOutput + "\n");
|
|
5170
5227
|
if (ok) resolve();
|
|
5171
5228
|
else process.stdout.once("drain", resolve);
|