@lateos/npm-scan 0.7.4 → 0.7.5

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 CHANGED
@@ -21,7 +21,7 @@ npx @lateos/npm-scan scan lodash
21
21
  - **SBOM Output** — CycloneDX 1.5 and SPDX 2.3 with findings mapped as vulnerabilities
22
22
  - **NIST 800-161 Compliance** — HTML report includes control traceability matrix (SR-2.1 → SR-11.4)
23
23
  - **EU CRA Compliance** — report maps findings to Cyber Resilience Act articles and Annex I requirements
24
- - **SIEM Export** — CEF format for Splunk and other SIEM ingestion (premium)
24
+ - **SIEM Export** — Splunk CEF, Elastic ECS, Microsoft Sentinel, IBM QRadar formats (premium)
25
25
  - **EU CRA Compliance** — report maps findings to Cyber Resilience Act articles (premium)
26
26
  - **License Key Gating** — premium features locked behind signed license keys
27
27
  - **REST API** — FastAPI-based API with webhooks, auth, scan management (premium)
@@ -47,7 +47,7 @@ npm-scan report -i <id> --sbom spdx Generate SPDX SBOM
47
47
  npm-scan report -i <id> --html Generate HTML report (with NIST table)
48
48
  npm-scan report -i <id> --nist Print NIST 800-161 compliance table
49
49
  npm-scan report -i <id> --cra Print EU CRA compliance table
50
- npm-scan report -i <id> --siem cef Generate SIEM CEF output (premium)
50
+ npm-scan report -i <id> --siem <fmt> Generate SIEM output (cef|ecs|sentinel|qradar) (premium)
51
51
  npm-scan report --html Generate HTML report for all scans
52
52
  npm-scan report --nist Print NIST compliance for all scans
53
53
  npm-scan report --cra Print EU CRA compliance for all scans (premium)
@@ -0,0 +1,41 @@
1
+ export function generateECS(scans) {
2
+ const events = [];
3
+ for (const s of scans) {
4
+ for (const f of (s.findings || [])) {
5
+ const atkId = f.atk_id || f.id;
6
+ const sevMap = { critical: 100, high: 80, medium: 50, low: 20 };
7
+ events.push({
8
+ '@timestamp': new Date().toISOString(),
9
+ event: {
10
+ kind: 'alert',
11
+ category: 'threat',
12
+ type: ['indicator', 'threat'],
13
+ action: 'npm-scan-detected',
14
+ severity: sevMap[f.severity] || 50,
15
+ },
16
+ message: `[${atkId}] ${f.severity.toUpperCase()}: ${f.description || f.title || 'Unknown finding'}`,
17
+ log: { level: f.severity },
18
+ observer: {
19
+ vendor: 'Lateos',
20
+ product: 'npm-scan',
21
+ version: process.env.npm_package_version || '0.7.0',
22
+ },
23
+ labels: {
24
+ package: s.package_name || 'unknown',
25
+ version: s.version || 'unknown',
26
+ atk_id: atkId,
27
+ severity: f.severity,
28
+ },
29
+ vulnerability: {
30
+ classification: 'npm-supply-chain',
31
+ reference: `https://npm-scan.io/atk/${atkId}`,
32
+ id: atkId,
33
+ description: f.description || f.title || null,
34
+ enumeration: 'ATK',
35
+ },
36
+ file: f.evidence ? { name: f.evidence } : undefined,
37
+ });
38
+ }
39
+ }
40
+ return events.map(e => JSON.stringify(e)).join('\n');
41
+ }
@@ -1,10 +1,19 @@
1
1
  import { generateCEF } from './cef.js';
2
+ import { generateECS } from './ecs.js';
3
+ import { generateSentinel } from './sentinel.js';
4
+ import { generateQRadar } from './qradar.js';
2
5
 
3
6
  export function generateSIEM(scans, format = 'cef') {
4
7
  switch (format) {
5
8
  case 'cef':
6
9
  return generateCEF(scans);
10
+ case 'ecs':
11
+ return generateECS(scans);
12
+ case 'sentinel':
13
+ return generateSentinel(scans);
14
+ case 'qradar':
15
+ return generateQRadar(scans);
7
16
  default:
8
- throw new Error(`Unknown SIEM format: ${format}`);
17
+ throw new Error(`Unknown SIEM format: ${format}. Supported: cef, ecs, sentinel, qradar`);
9
18
  }
10
19
  }
@@ -0,0 +1,57 @@
1
+ export function generateQRadar(scans) {
2
+ const events = [];
3
+ for (const s of scans) {
4
+ for (const f of (s.findings || [])) {
5
+ const atkId = f.atk_id || f.id;
6
+ events.push({
7
+ source: 'npm-scan',
8
+ version: process.env.npm_package_version || '0.7.0',
9
+ devicetime: new Date().toISOString(),
10
+ devicepayload: [
11
+ s.package_name || 'unknown',
12
+ s.version || 'unknown',
13
+ atkId,
14
+ f.severity,
15
+ f.title || f.description || '',
16
+ f.evidence || '',
17
+ ].join('\t'),
18
+ devicevendor: 'Lateos',
19
+ devicename: 'npm-scan',
20
+ deviceproduct: 'npm-scan',
21
+ atk_id: atkId,
22
+ severity: f.severity,
23
+ package_name: s.package_name || 'unknown',
24
+ package_version: s.version || 'unknown',
25
+ finding_title: f.title || f.description || '',
26
+ finding_description: f.description || f.title || '',
27
+ evidence: f.evidence || '',
28
+ mitigation: f.mitigation || '',
29
+ raw_category: 'NPM Supply Chain Threat',
30
+ qid: _qrQid(f.severity),
31
+ category: _qrCategory(f.severity),
32
+ });
33
+ }
34
+ }
35
+ return events.map(e => JSON.stringify(e)).join('\n');
36
+ }
37
+
38
+ const QID_MAP = {
39
+ critical: 90050001,
40
+ high: 90050002,
41
+ medium: 90050003,
42
+ low: 90050004,
43
+ };
44
+
45
+ function _qrQid(severity) {
46
+ return QID_MAP[severity] || 90050003;
47
+ }
48
+
49
+ function _qrCategory(severity) {
50
+ const map = {
51
+ critical: 'Critical Severity Malware',
52
+ high: 'High Severity Malware',
53
+ medium: 'Medium Severity Malware',
54
+ low: 'Low Severity Malware',
55
+ };
56
+ return map[severity] || 'Medium Severity Malware';
57
+ }
@@ -0,0 +1,28 @@
1
+ export function generateSentinel(scans) {
2
+ const events = [];
3
+ for (const s of scans) {
4
+ for (const f of (s.findings || [])) {
5
+ const atkId = f.atk_id || f.id;
6
+ events.push({
7
+ TimeGenerated: new Date().toISOString(),
8
+ Computer: process.env.COMPUTERNAME || process.env.HOSTNAME || 'npm-scan-host',
9
+ SourceSystem: 'npm-scan',
10
+ DeviceVendor: 'Lateos',
11
+ DeviceProduct: 'npm-scan',
12
+ DeviceVersion: process.env.npm_package_version || '0.7.0',
13
+ SeverityLevel: f.severity,
14
+ Severity: f.severity.toUpperCase(),
15
+ EventType: 'npm-supply-chain-threat',
16
+ ATKId: atkId,
17
+ FindingTitle: f.title || f.description || '',
18
+ FindingDescription: f.description || f.title || '',
19
+ Evidence: f.evidence || '',
20
+ PackageName: s.package_name || 'unknown',
21
+ PackageVersion: s.version || 'unknown',
22
+ Mitigation: f.mitigation || '',
23
+ ThreatClassification: 'npm-supply-chain',
24
+ });
25
+ }
26
+ }
27
+ return JSON.stringify(events, null, 2);
28
+ }
package/cli/cli.js CHANGED
@@ -60,7 +60,7 @@ program
60
60
  .option('--html', 'HTML report')
61
61
  .option('--nist', 'NIST 800-161 compliance report')
62
62
  .option('--cra', 'EU CRA compliance report')
63
- .option('--siem <format>', 'SIEM format (cef)')
63
+ .option('--siem <format>', 'SIEM format (cef|ecs|sentinel|qradar)')
64
64
  .option('-l, --license-key <key>', 'Premium license')
65
65
  .action(async (options) => {
66
66
  const licenseKey = options.licenseKey || process.env.NPM_SCAN_LICENSE_KEY;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lateos/npm-scan",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "description": "Powerful npm supply chain security scanner - detects malicious packages (Shai-Hulud style), behavioral analysis, SBOM, and compliance reporting.",
5
5
  "main": "backend/index.js",
6
6
  "bin": {