@maverick006/scanner-npm-audit 1.0.5 → 1.0.6

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/package.json CHANGED
@@ -1,23 +1,27 @@
1
- {
2
- "name": "@maverick006/scanner-npm-audit",
3
- "version": "1.0.5",
4
- "main": "dist/index.js",
5
- "types": "dist/index.d.ts",
6
- "scripts": {
7
- "build": "tsc",
8
- "clean": "rm -rf dist",
9
- "test": "jest",
10
- "typecheck": "tsc --noEmit"
11
- },
12
- "dependencies": {
13
- "@maverick006/types": "*",
14
- "@maverick006/security-engine": "*"
15
- },
16
- "devDependencies": {
17
- "typescript": "^5.0.0",
18
- "jest": "^29.5.0",
19
- "@types/jest": "^29.5.0",
20
- "ts-jest": "^29.1.0",
21
- "@types/node": "^20.0.0"
22
- }
23
- }
1
+ {
2
+ "name": "@maverick006/scanner-npm-audit",
3
+ "version": "1.0.6",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "scripts": {
7
+ "build": "tsc -b --force",
8
+ "clean": "rm -rf dist",
9
+ "test": "jest",
10
+ "typecheck": "tsc --noEmit",
11
+ "prepack": "npm run build"
12
+ },
13
+ "dependencies": {
14
+ "@maverick006/types": "^1.0.5",
15
+ "@maverick006/security-engine": "^1.0.5"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.0.0",
19
+ "jest": "^29.5.0",
20
+ "@types/jest": "^29.5.0",
21
+ "ts-jest": "^29.1.0",
22
+ "@types/node": "^20.0.0"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ]
27
+ }
package/jest.config.js DELETED
@@ -1,5 +0,0 @@
1
- /** @type {import('ts-jest').JestConfigWithTsJest} */
2
- module.exports = {
3
- preset: 'ts-jest',
4
- testEnvironment: 'node',
5
- };
package/src/index.ts DELETED
@@ -1,135 +0,0 @@
1
- import { SecurityScanner, ScannerCapability } from '@maverick006/security-engine';
2
- import { ScanInput, ScannerResult, ScannerState } from '@maverick006/types';
3
- import { execFile } from 'child_process';
4
- import { promisify } from 'util';
5
- import { parseNpmAuditOutput } from './parser';
6
- import * as path from 'path';
7
- import * as fs from 'fs';
8
-
9
- const execFileAsync = promisify(execFile);
10
-
11
- export class NpmAuditScanner implements SecurityScanner {
12
- public name = 'npm-audit';
13
- public version = 'unknown';
14
-
15
- public capabilities: ScannerCapability = {
16
- category: 'dependencies',
17
- detectApplicability: (repoPath: string) => {
18
- const safePath = path.resolve(repoPath);
19
- return fs.existsSync(path.join(safePath, 'package.json'));
20
- }
21
- };
22
-
23
- async scan(input: ScanInput): Promise<ScannerResult> {
24
- const startTime = new Date();
25
- let rawOutput = '';
26
-
27
- const safePath = path.resolve(input.repositoryPath);
28
- const hasPackageJson = fs.existsSync(path.join(safePath, 'package.json'));
29
-
30
- if (!hasPackageJson) {
31
- const endTime = new Date();
32
- return {
33
- scanner: this.name,
34
- success: true,
35
- state: ScannerState.SKIPPED,
36
- reason: 'Skipped: No package.json detected in repository',
37
- findings: [],
38
- rawOutput: 'No package.json found',
39
- startTime,
40
- endTime,
41
- durationMs: endTime.getTime() - startTime.getTime()
42
- };
43
- }
44
-
45
- try {
46
- const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
47
- const args = ['audit', '--json'];
48
-
49
- const { stdout } = await execFileAsync(npmCmd, args, {
50
- cwd: safePath,
51
- timeout: 60000,
52
- maxBuffer: 1024 * 1024 * 50,
53
- shell: process.platform === 'win32'
54
- });
55
-
56
- rawOutput = stdout;
57
- const findings = parseNpmAuditOutput(input.scanId, rawOutput);
58
- const endTime = new Date();
59
-
60
- return {
61
- scanner: this.name,
62
- success: true,
63
- state: ScannerState.SUCCESS,
64
- findings,
65
- rawOutput,
66
- startTime,
67
- endTime,
68
- durationMs: endTime.getTime() - startTime.getTime()
69
- };
70
- } catch (error: any) {
71
- const endTime = new Date();
72
- const durationMs = endTime.getTime() - startTime.getTime();
73
-
74
- if (error.code === 'ENOENT') {
75
- return {
76
- scanner: this.name,
77
- success: false,
78
- state: ScannerState.NOT_INSTALLED,
79
- reason: 'npm executable was not found on PATH',
80
- findings: [],
81
- error: error.message,
82
- startTime,
83
- endTime,
84
- durationMs
85
- };
86
- }
87
-
88
- if (error.code === 'ETIMEDOUT') {
89
- return {
90
- scanner: this.name,
91
- success: false,
92
- state: ScannerState.TIMEOUT,
93
- reason: 'npm-audit execution timed out',
94
- findings: [],
95
- error: error.message,
96
- startTime,
97
- endTime,
98
- durationMs
99
- };
100
- }
101
-
102
- // npm audit exits > 0 if vulnerabilities are found
103
- if (error.stdout && error.stdout.includes('"auditReportVersion":')) {
104
- try {
105
- rawOutput = error.stdout;
106
- const findings = parseNpmAuditOutput(input.scanId, rawOutput);
107
- return {
108
- scanner: this.name,
109
- success: true,
110
- state: ScannerState.SUCCESS,
111
- findings,
112
- rawOutput,
113
- startTime,
114
- endTime,
115
- durationMs
116
- };
117
- } catch {
118
- // ignore parsing error
119
- }
120
- }
121
-
122
- return {
123
- scanner: this.name,
124
- success: false,
125
- state: ScannerState.FAILED,
126
- findings: [],
127
- error: error.message || 'npm audit execution failed',
128
- rawOutput: error.stdout || '',
129
- startTime,
130
- endTime,
131
- durationMs
132
- };
133
- }
134
- }
135
- }
package/src/parser.ts DELETED
@@ -1,55 +0,0 @@
1
- import { NormalizedFinding, Severity, Confidence } from '@maverick006/types';
2
-
3
- export function parseNpmAuditOutput(scanId: string, output: string): NormalizedFinding[] {
4
- try {
5
- const data = JSON.parse(output);
6
- const findings: NormalizedFinding[] = [];
7
-
8
- // npm audit JSON output format: version 2
9
- if (data.auditReportVersion !== 2 || !data.vulnerabilities) {
10
- return findings;
11
- }
12
-
13
- for (const [pkgName, vulnData] of Object.entries<any>(data.vulnerabilities)) {
14
-
15
- const viaArray = Array.isArray(vulnData.via) ? vulnData.via : [];
16
-
17
- // Some 'via' entries are just strings (referencing other packages),
18
- // we look for objects that contain actual vulnerability details.
19
- for (const via of viaArray) {
20
- if (typeof via === 'object' && via.title) {
21
-
22
- let severity = Severity.INFO;
23
- if (via.severity === 'critical') severity = Severity.CRITICAL;
24
- else if (via.severity === 'high') severity = Severity.HIGH;
25
- else if (via.severity === 'moderate') severity = Severity.MEDIUM;
26
- else if (via.severity === 'low') severity = Severity.LOW;
27
-
28
- const finding: NormalizedFinding = {
29
- scanId,
30
- scanner: 'npm-audit',
31
- scannerVersion: 'v2', // refers to report version
32
- ruleId: via.url || `npm-audit-${pkgName}`,
33
- title: via.title,
34
- description: `Dependency vulnerability in ${pkgName}. Range: ${via.range}. Fix: ${
35
- vulnData.fixAvailable ? (typeof vulnData.fixAvailable === 'object' ? vulnData.fixAvailable.name + '@' + vulnData.fixAvailable.version : 'Available') : 'None'
36
- }`,
37
- severity,
38
- confidence: Confidence.HIGH, // SCA scans matching a CVE have high confidence
39
- category: 'dependency',
40
- file: 'package.json', // Best guess for location
41
- line: 1, // Doesn't map well to line numbers
42
- cwe: Array.isArray(via.cwe) ? via.cwe.join(', ') : via.cwe,
43
- owasp: 'A06:2021', // Vulnerable and Outdated Components
44
- };
45
-
46
- findings.push(finding);
47
- }
48
- }
49
- }
50
-
51
- return findings;
52
- } catch (error) {
53
- throw new Error('Failed to parse npm audit JSON output');
54
- }
55
- }
@@ -1,87 +0,0 @@
1
- {
2
- "auditReportVersion": 2,
3
- "vulnerabilities": {
4
- "express": {
5
- "name": "express",
6
- "severity": "high",
7
- "isDirect": true,
8
- "via": [
9
- {
10
- "source": 1085149,
11
- "name": "express",
12
- "dependency": "express",
13
- "title": "Path Traversal in express",
14
- "url": "https://github.com/advisories/GHSA-9234-5678",
15
- "severity": "high",
16
- "cwe": [
17
- "CWE-22"
18
- ],
19
- "cvss": {
20
- "score": 7.5,
21
- "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
22
- },
23
- "range": "<4.19.2"
24
- }
25
- ],
26
- "effects": [],
27
- "range": "<4.19.2",
28
- "nodes": [
29
- "node_modules/express"
30
- ],
31
- "fixAvailable": {
32
- "name": "express",
33
- "version": "4.19.2",
34
- "isSemVerMajor": false
35
- }
36
- },
37
- "lodash": {
38
- "name": "lodash",
39
- "severity": "critical",
40
- "isDirect": false,
41
- "via": [
42
- {
43
- "source": 1012345,
44
- "name": "lodash",
45
- "dependency": "lodash",
46
- "title": "Prototype Pollution in lodash",
47
- "url": "https://github.com/advisories/GHSA-1234-abcd",
48
- "severity": "critical",
49
- "cwe": [
50
- "CWE-1321"
51
- ],
52
- "cvss": {
53
- "score": 9.8,
54
- "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
55
- },
56
- "range": "<4.17.21"
57
- }
58
- ],
59
- "effects": [
60
- "some-other-pkg"
61
- ],
62
- "range": "<4.17.21",
63
- "nodes": [
64
- "node_modules/lodash"
65
- ],
66
- "fixAvailable": true
67
- }
68
- },
69
- "metadata": {
70
- "vulnerabilities": {
71
- "info": 0,
72
- "low": 0,
73
- "moderate": 0,
74
- "high": 1,
75
- "critical": 1,
76
- "total": 2
77
- },
78
- "dependencies": {
79
- "prod": 10,
80
- "dev": 20,
81
- "optional": 0,
82
- "peer": 0,
83
- "peerOptional": 0,
84
- "total": 30
85
- }
86
- }
87
- }
@@ -1,41 +0,0 @@
1
- import { parseNpmAuditOutput } from '../src/parser';
2
- import * as fs from 'fs';
3
- import * as path from 'path';
4
- import { Severity, Confidence } from '@maverick006/types';
5
-
6
- describe('npm audit Parser', () => {
7
- it('should parse npm audit json output correctly', () => {
8
- const fixturePath = path.join(__dirname, 'fixtures', 'npm-audit-output.json');
9
- const output = fs.readFileSync(fixturePath, 'utf8');
10
-
11
- const findings = parseNpmAuditOutput('test-scan-123', output);
12
-
13
- expect(findings.length).toBe(2);
14
-
15
- // Check first finding (express Path Traversal)
16
- const expressVuln = findings[0];
17
- expect(expressVuln.scanId).toBe('test-scan-123');
18
- expect(expressVuln.scanner).toBe('npm-audit');
19
- expect(expressVuln.title).toBe('Path Traversal in express');
20
- expect(expressVuln.severity).toBe(Severity.HIGH);
21
- expect(expressVuln.confidence).toBe(Confidence.HIGH);
22
- expect(expressVuln.cwe).toContain('CWE-22');
23
- expect(expressVuln.file).toBe('package.json');
24
- expect(expressVuln.category).toBe('dependency');
25
- expect(expressVuln.description).toContain('Fix: express@4.19.2');
26
-
27
- // Check second finding (lodash Prototype Pollution)
28
- const lodashVuln = findings[1];
29
- expect(lodashVuln.title).toBe('Prototype Pollution in lodash');
30
- expect(lodashVuln.severity).toBe(Severity.CRITICAL);
31
- expect(lodashVuln.cwe).toContain('CWE-1321');
32
- expect(lodashVuln.description).toContain('Fix: Available');
33
- });
34
-
35
- it('should handle malformed output gracefully', () => {
36
- expect(() => parseNpmAuditOutput('123', '{ invalid json }')).toThrow();
37
-
38
- const emptyFindings = parseNpmAuditOutput('123', '{"auditReportVersion": 2, "vulnerabilities": {}}');
39
- expect(emptyFindings.length).toBe(0);
40
- });
41
- });
package/tsconfig.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "./dist",
5
- "rootDir": "./src",
6
- "declaration": true,
7
- "declarationMap": true,
8
- "sourceMap": true
9
- },
10
- "references": [
11
- { "path": "../../packages/types" },
12
- { "path": "../../packages/security-engine" }
13
- ],
14
- "include": ["src/**/*"]
15
- }