ghostpatch 1.0.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.
- package/LICENSE +21 -0
- package/README.md +213 -0
- package/__tests__/detectors.test.ts +224 -0
- package/__tests__/rules.test.ts +117 -0
- package/__tests__/scanner.test.ts +222 -0
- package/dist/ai/anthropic.d.ts +11 -0
- package/dist/ai/anthropic.d.ts.map +1 -0
- package/dist/ai/anthropic.js +76 -0
- package/dist/ai/anthropic.js.map +1 -0
- package/dist/ai/huggingface.d.ts +12 -0
- package/dist/ai/huggingface.d.ts.map +1 -0
- package/dist/ai/huggingface.js +95 -0
- package/dist/ai/huggingface.js.map +1 -0
- package/dist/ai/openai.d.ts +11 -0
- package/dist/ai/openai.d.ts.map +1 -0
- package/dist/ai/openai.js +71 -0
- package/dist/ai/openai.js.map +1 -0
- package/dist/ai/prompts.d.ts +5 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +101 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/provider.d.ts +9 -0
- package/dist/ai/provider.d.ts.map +1 -0
- package/dist/ai/provider.js +66 -0
- package/dist/ai/provider.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +318 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/reporter.d.ts +7 -0
- package/dist/core/reporter.d.ts.map +1 -0
- package/dist/core/reporter.js +366 -0
- package/dist/core/reporter.js.map +1 -0
- package/dist/core/rules.d.ts +8 -0
- package/dist/core/rules.d.ts.map +1 -0
- package/dist/core/rules.js +1077 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/scanner.d.ts +6 -0
- package/dist/core/scanner.d.ts.map +1 -0
- package/dist/core/scanner.js +217 -0
- package/dist/core/scanner.js.map +1 -0
- package/dist/core/severity.d.ts +100 -0
- package/dist/core/severity.d.ts.map +1 -0
- package/dist/core/severity.js +52 -0
- package/dist/core/severity.js.map +1 -0
- package/dist/detectors/auth.d.ts +3 -0
- package/dist/detectors/auth.d.ts.map +1 -0
- package/dist/detectors/auth.js +138 -0
- package/dist/detectors/auth.js.map +1 -0
- package/dist/detectors/crypto.d.ts +3 -0
- package/dist/detectors/crypto.d.ts.map +1 -0
- package/dist/detectors/crypto.js +128 -0
- package/dist/detectors/crypto.js.map +1 -0
- package/dist/detectors/dependency.d.ts +4 -0
- package/dist/detectors/dependency.d.ts.map +1 -0
- package/dist/detectors/dependency.js +267 -0
- package/dist/detectors/dependency.js.map +1 -0
- package/dist/detectors/deserialize.d.ts +3 -0
- package/dist/detectors/deserialize.d.ts.map +1 -0
- package/dist/detectors/deserialize.js +107 -0
- package/dist/detectors/deserialize.js.map +1 -0
- package/dist/detectors/injection.d.ts +3 -0
- package/dist/detectors/injection.d.ts.map +1 -0
- package/dist/detectors/injection.js +158 -0
- package/dist/detectors/injection.js.map +1 -0
- package/dist/detectors/misconfig.d.ts +3 -0
- package/dist/detectors/misconfig.d.ts.map +1 -0
- package/dist/detectors/misconfig.js +153 -0
- package/dist/detectors/misconfig.js.map +1 -0
- package/dist/detectors/pathtraversal.d.ts +3 -0
- package/dist/detectors/pathtraversal.d.ts.map +1 -0
- package/dist/detectors/pathtraversal.js +90 -0
- package/dist/detectors/pathtraversal.js.map +1 -0
- package/dist/detectors/prototype.d.ts +3 -0
- package/dist/detectors/prototype.d.ts.map +1 -0
- package/dist/detectors/prototype.js +79 -0
- package/dist/detectors/prototype.js.map +1 -0
- package/dist/detectors/secrets.d.ts +4 -0
- package/dist/detectors/secrets.d.ts.map +1 -0
- package/dist/detectors/secrets.js +137 -0
- package/dist/detectors/secrets.js.map +1 -0
- package/dist/detectors/ssrf.d.ts +3 -0
- package/dist/detectors/ssrf.d.ts.map +1 -0
- package/dist/detectors/ssrf.js +78 -0
- package/dist/detectors/ssrf.js.map +1 -0
- package/dist/detectors/zeroday.d.ts +9 -0
- package/dist/detectors/zeroday.d.ts.map +1 -0
- package/dist/detectors/zeroday.js +77 -0
- package/dist/detectors/zeroday.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +358 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/utils/config.d.ts +4 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +97 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/fingerprint.d.ts +5 -0
- package/dist/utils/fingerprint.d.ts.map +1 -0
- package/dist/utils/fingerprint.js +55 -0
- package/dist/utils/fingerprint.js.map +1 -0
- package/dist/utils/languages.d.ts +8 -0
- package/dist/utils/languages.d.ts.map +1 -0
- package/dist/utils/languages.js +128 -0
- package/dist/utils/languages.js.map +1 -0
- package/package.json +53 -0
- package/src/ai/anthropic.ts +82 -0
- package/src/ai/huggingface.ts +111 -0
- package/src/ai/openai.ts +75 -0
- package/src/ai/prompts.ts +100 -0
- package/src/ai/provider.ts +68 -0
- package/src/cli/index.ts +314 -0
- package/src/core/reporter.ts +356 -0
- package/src/core/rules.ts +1089 -0
- package/src/core/scanner.ts +201 -0
- package/src/core/severity.ts +140 -0
- package/src/detectors/auth.ts +152 -0
- package/src/detectors/crypto.ts +128 -0
- package/src/detectors/dependency.ts +240 -0
- package/src/detectors/deserialize.ts +106 -0
- package/src/detectors/injection.ts +172 -0
- package/src/detectors/misconfig.ts +152 -0
- package/src/detectors/pathtraversal.ts +89 -0
- package/src/detectors/prototype.ts +77 -0
- package/src/detectors/secrets.ts +138 -0
- package/src/detectors/ssrf.ts +77 -0
- package/src/detectors/zeroday.ts +93 -0
- package/src/index.ts +24 -0
- package/src/mcp/server.ts +379 -0
- package/src/utils/config.ts +64 -0
- package/src/utils/fingerprint.ts +21 -0
- package/src/utils/languages.ts +95 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
import { scan, scanFile } from '../src/core/scanner';
|
|
6
|
+
import { generateReport } from '../src/core/reporter';
|
|
7
|
+
import { Severity } from '../src/core/severity';
|
|
8
|
+
import { detectLanguage, isSupportedFile } from '../src/utils/languages';
|
|
9
|
+
import { generateFingerprint, deduplicateFindings } from '../src/utils/fingerprint';
|
|
10
|
+
|
|
11
|
+
describe('Scanner', () => {
|
|
12
|
+
it('should scan a single file', () => {
|
|
13
|
+
const code = `
|
|
14
|
+
const password = "admin";
|
|
15
|
+
eval(userInput);
|
|
16
|
+
db.query("SELECT * FROM users WHERE id=" + userId);
|
|
17
|
+
`;
|
|
18
|
+
const findings = scanFile('test.js', code, 'javascript');
|
|
19
|
+
expect(findings.length).toBeGreaterThan(0);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should detect multiple vulnerability types', () => {
|
|
23
|
+
const code = `
|
|
24
|
+
eval(userInput);
|
|
25
|
+
db.query("SELECT * FROM users WHERE id=" + userId);
|
|
26
|
+
element.innerHTML = userData;
|
|
27
|
+
const key = "AKIAIOSFODNN7EXAMPLE";
|
|
28
|
+
`;
|
|
29
|
+
const findings = scanFile('test.js', code, 'javascript');
|
|
30
|
+
const ruleIds = new Set(findings.map(f => f.ruleId));
|
|
31
|
+
expect(ruleIds.size).toBeGreaterThanOrEqual(3);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should scan a directory', async () => {
|
|
35
|
+
// Create temp dir with test files
|
|
36
|
+
const tmpDir = path.join(os.tmpdir(), 'ghostpatch-test-' + Date.now());
|
|
37
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
38
|
+
|
|
39
|
+
fs.writeFileSync(path.join(tmpDir, 'test.js'), `
|
|
40
|
+
const password = "admin";
|
|
41
|
+
eval(userInput);
|
|
42
|
+
`);
|
|
43
|
+
fs.writeFileSync(path.join(tmpDir, 'safe.js'), `
|
|
44
|
+
const x = 1 + 2;
|
|
45
|
+
console.log(x);
|
|
46
|
+
`);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const result = await scan(tmpDir, { severity: Severity.LOW });
|
|
50
|
+
expect(result.filesScanned).toBeGreaterThanOrEqual(2);
|
|
51
|
+
expect(result.findings.length).toBeGreaterThan(0);
|
|
52
|
+
expect(result.summary.total).toBe(result.findings.length);
|
|
53
|
+
expect(result.durationMs).toBeGreaterThanOrEqual(0);
|
|
54
|
+
} finally {
|
|
55
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should filter by severity', async () => {
|
|
60
|
+
const code = `
|
|
61
|
+
const password = "admin";
|
|
62
|
+
eval(userInput);
|
|
63
|
+
element.innerHTML = userData;
|
|
64
|
+
const x = Math.random();
|
|
65
|
+
const opts = { secure: false, httpOnly: false };
|
|
66
|
+
`;
|
|
67
|
+
const allFindings = scanFile('test.js', code, 'javascript');
|
|
68
|
+
const criticalFindings = allFindings.filter(f => f.severity === Severity.CRITICAL);
|
|
69
|
+
expect(allFindings.length).toBeGreaterThan(0);
|
|
70
|
+
expect(criticalFindings.length).toBeGreaterThan(0);
|
|
71
|
+
expect(criticalFindings.length).toBeLessThanOrEqual(allFindings.length);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should include code snippets', () => {
|
|
75
|
+
const code = `line1
|
|
76
|
+
line2
|
|
77
|
+
eval(userInput);
|
|
78
|
+
line4
|
|
79
|
+
line5`;
|
|
80
|
+
const findings = scanFile('test.js', code, 'javascript');
|
|
81
|
+
const evalFinding = findings.find(f => f.ruleId.includes('EVAL'));
|
|
82
|
+
if (evalFinding) {
|
|
83
|
+
expect(evalFinding.codeSnippet).toContain('eval');
|
|
84
|
+
expect(evalFinding.line).toBe(3);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should produce valid fingerprints', () => {
|
|
89
|
+
const code = 'eval(userInput);';
|
|
90
|
+
const findings = scanFile('test.js', code, 'javascript');
|
|
91
|
+
for (const f of findings) {
|
|
92
|
+
expect(f.fingerprint).toBeTruthy();
|
|
93
|
+
expect(f.fingerprint.length).toBe(16);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('Reporter', () => {
|
|
99
|
+
it('should generate terminal report', async () => {
|
|
100
|
+
const tmpDir = path.join(os.tmpdir(), 'ghostpatch-report-test-' + Date.now());
|
|
101
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
102
|
+
fs.writeFileSync(path.join(tmpDir, 'test.js'), 'eval(userInput);');
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const result = await scan(tmpDir);
|
|
106
|
+
const report = generateReport(result, 'terminal');
|
|
107
|
+
expect(report).toContain('GhostPatch');
|
|
108
|
+
expect(report).toContain('CRITICAL');
|
|
109
|
+
} finally {
|
|
110
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should generate JSON report', async () => {
|
|
115
|
+
const tmpDir = path.join(os.tmpdir(), 'ghostpatch-json-test-' + Date.now());
|
|
116
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
117
|
+
fs.writeFileSync(path.join(tmpDir, 'test.js'), 'eval(userInput);');
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const result = await scan(tmpDir);
|
|
121
|
+
const json = generateReport(result, 'json');
|
|
122
|
+
const parsed = JSON.parse(json);
|
|
123
|
+
expect(parsed.ghostpatch.version).toBe('1.0.0');
|
|
124
|
+
expect(Array.isArray(parsed.findings)).toBe(true);
|
|
125
|
+
} finally {
|
|
126
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should generate SARIF report', async () => {
|
|
131
|
+
const tmpDir = path.join(os.tmpdir(), 'ghostpatch-sarif-test-' + Date.now());
|
|
132
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
133
|
+
fs.writeFileSync(path.join(tmpDir, 'test.js'), 'eval(userInput);');
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const result = await scan(tmpDir);
|
|
137
|
+
const sarif = generateReport(result, 'sarif');
|
|
138
|
+
const parsed = JSON.parse(sarif);
|
|
139
|
+
expect(parsed.version).toBe('2.1.0');
|
|
140
|
+
expect(parsed.runs).toBeDefined();
|
|
141
|
+
expect(parsed.runs[0].tool.driver.name).toBe('GhostPatch');
|
|
142
|
+
} finally {
|
|
143
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should generate HTML report', async () => {
|
|
148
|
+
const tmpDir = path.join(os.tmpdir(), 'ghostpatch-html-test-' + Date.now());
|
|
149
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
150
|
+
fs.writeFileSync(path.join(tmpDir, 'test.js'), 'eval(userInput);');
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
const result = await scan(tmpDir);
|
|
154
|
+
const html = generateReport(result, 'html');
|
|
155
|
+
expect(html).toContain('<!DOCTYPE html>');
|
|
156
|
+
expect(html).toContain('GhostPatch');
|
|
157
|
+
expect(html).toContain('Security Report');
|
|
158
|
+
} finally {
|
|
159
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe('Language Detection', () => {
|
|
165
|
+
it('should detect JavaScript', () => {
|
|
166
|
+
expect(detectLanguage('test.js')).toBe('javascript');
|
|
167
|
+
expect(detectLanguage('test.jsx')).toBe('javascript');
|
|
168
|
+
expect(detectLanguage('test.mjs')).toBe('javascript');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should detect TypeScript', () => {
|
|
172
|
+
expect(detectLanguage('test.ts')).toBe('typescript');
|
|
173
|
+
expect(detectLanguage('test.tsx')).toBe('typescript');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should detect Python', () => {
|
|
177
|
+
expect(detectLanguage('test.py')).toBe('python');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should detect Java', () => {
|
|
181
|
+
expect(detectLanguage('Test.java')).toBe('java');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should detect Go', () => {
|
|
185
|
+
expect(detectLanguage('main.go')).toBe('go');
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should return null for unsupported files', () => {
|
|
189
|
+
expect(detectLanguage('test.txt')).toBeNull();
|
|
190
|
+
expect(detectLanguage('image.png')).toBeNull();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should identify supported files', () => {
|
|
194
|
+
expect(isSupportedFile('test.ts')).toBe(true);
|
|
195
|
+
expect(isSupportedFile('test.py')).toBe(true);
|
|
196
|
+
expect(isSupportedFile('test.txt')).toBe(false);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('Fingerprinting', () => {
|
|
201
|
+
it('should generate consistent fingerprints', () => {
|
|
202
|
+
const fp1 = generateFingerprint('rule1', 'file1', 'content');
|
|
203
|
+
const fp2 = generateFingerprint('rule1', 'file1', 'content');
|
|
204
|
+
expect(fp1).toBe(fp2);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should generate different fingerprints for different inputs', () => {
|
|
208
|
+
const fp1 = generateFingerprint('rule1', 'file1', 'content1');
|
|
209
|
+
const fp2 = generateFingerprint('rule1', 'file1', 'content2');
|
|
210
|
+
expect(fp1).not.toBe(fp2);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should deduplicate findings', () => {
|
|
214
|
+
const findings = [
|
|
215
|
+
{ fingerprint: 'aaa', title: 'Finding 1' },
|
|
216
|
+
{ fingerprint: 'bbb', title: 'Finding 2' },
|
|
217
|
+
{ fingerprint: 'aaa', title: 'Finding 1 duplicate' },
|
|
218
|
+
];
|
|
219
|
+
const deduped = deduplicateFindings(findings);
|
|
220
|
+
expect(deduped.length).toBe(2);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AIFinding } from '../core/severity';
|
|
2
|
+
import { AIProvider } from './provider';
|
|
3
|
+
export declare class AnthropicProvider implements AIProvider {
|
|
4
|
+
name: string;
|
|
5
|
+
private apiKey;
|
|
6
|
+
constructor();
|
|
7
|
+
isAvailable(): boolean;
|
|
8
|
+
analyze(code: string, context: string): Promise<AIFinding[]>;
|
|
9
|
+
private callDirectAPI;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/ai/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AAGzD,qBAAa,iBAAkB,YAAW,UAAU;IAClD,IAAI,SAAe;IACnB,OAAO,CAAC,MAAM,CAAqB;;IAMnC,WAAW,IAAI,OAAO;IAIhB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YAmCpD,aAAa;CA8B5B"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AnthropicProvider = void 0;
|
|
4
|
+
const provider_1 = require("./provider");
|
|
5
|
+
const prompts_1 = require("./prompts");
|
|
6
|
+
class AnthropicProvider {
|
|
7
|
+
name = 'anthropic';
|
|
8
|
+
apiKey;
|
|
9
|
+
constructor() {
|
|
10
|
+
this.apiKey = process.env.ANTHROPIC_API_KEY;
|
|
11
|
+
}
|
|
12
|
+
isAvailable() {
|
|
13
|
+
return !!this.apiKey;
|
|
14
|
+
}
|
|
15
|
+
async analyze(code, context) {
|
|
16
|
+
if (!this.apiKey)
|
|
17
|
+
return [];
|
|
18
|
+
const prompt = (0, prompts_1.buildAnalysisPrompt)(code, context, 'security');
|
|
19
|
+
try {
|
|
20
|
+
// Try to use the SDK if available
|
|
21
|
+
const Anthropic = require('@anthropic-ai/sdk');
|
|
22
|
+
const client = new Anthropic({ apiKey: this.apiKey });
|
|
23
|
+
const response = await client.messages.create({
|
|
24
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
25
|
+
max_tokens: 4096,
|
|
26
|
+
messages: [{
|
|
27
|
+
role: 'user',
|
|
28
|
+
content: prompt,
|
|
29
|
+
}],
|
|
30
|
+
});
|
|
31
|
+
const text = response.content
|
|
32
|
+
.filter((c) => c.type === 'text')
|
|
33
|
+
.map((c) => c.text)
|
|
34
|
+
.join('');
|
|
35
|
+
return (0, provider_1.parseAIResponse)(text);
|
|
36
|
+
}
|
|
37
|
+
catch (sdkError) {
|
|
38
|
+
// Fallback to direct API call
|
|
39
|
+
try {
|
|
40
|
+
return await this.callDirectAPI(prompt);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async callDirectAPI(prompt) {
|
|
48
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
'x-api-key': this.apiKey,
|
|
53
|
+
'anthropic-version': '2023-06-01',
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
57
|
+
max_tokens: 4096,
|
|
58
|
+
messages: [{
|
|
59
|
+
role: 'user',
|
|
60
|
+
content: prompt,
|
|
61
|
+
}],
|
|
62
|
+
}),
|
|
63
|
+
});
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
throw new Error(`Anthropic API error: ${response.status}`);
|
|
66
|
+
}
|
|
67
|
+
const data = await response.json();
|
|
68
|
+
const text = data.content
|
|
69
|
+
?.filter((c) => c.type === 'text')
|
|
70
|
+
?.map((c) => c.text)
|
|
71
|
+
?.join('') || '';
|
|
72
|
+
return (0, provider_1.parseAIResponse)(text);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.AnthropicProvider = AnthropicProvider;
|
|
76
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/ai/anthropic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AIFinding } from '../core/severity';
|
|
2
|
+
import { AIProvider } from './provider';
|
|
3
|
+
export declare class HuggingFaceProvider implements AIProvider {
|
|
4
|
+
name: string;
|
|
5
|
+
private token;
|
|
6
|
+
private model;
|
|
7
|
+
constructor(model?: string);
|
|
8
|
+
isAvailable(): boolean;
|
|
9
|
+
analyze(code: string, context: string): Promise<AIFinding[]>;
|
|
10
|
+
private callAPI;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=huggingface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"huggingface.d.ts","sourceRoot":"","sources":["../../src/ai/huggingface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AAOzD,qBAAa,mBAAoB,YAAW,UAAU;IACpD,IAAI,SAAiB;IACrB,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAS;gBAEV,KAAK,CAAC,EAAE,MAAM;IAK1B,WAAW,IAAI,OAAO;IAIhB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YAiBpD,OAAO;CAoCtB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HuggingFaceProvider = void 0;
|
|
4
|
+
const provider_1 = require("./provider");
|
|
5
|
+
const prompts_1 = require("./prompts");
|
|
6
|
+
const DEFAULT_MODEL = 'Qwen/Qwen2.5-Coder-32B-Instruct';
|
|
7
|
+
const FALLBACK_MODEL = 'bigcode/starcoder2-15b';
|
|
8
|
+
const HF_API_URL = 'https://api-inference.huggingface.co/models';
|
|
9
|
+
class HuggingFaceProvider {
|
|
10
|
+
name = 'huggingface';
|
|
11
|
+
token;
|
|
12
|
+
model;
|
|
13
|
+
constructor(model) {
|
|
14
|
+
this.token = process.env.HF_TOKEN || process.env.HUGGINGFACE_TOKEN;
|
|
15
|
+
this.model = model || DEFAULT_MODEL;
|
|
16
|
+
}
|
|
17
|
+
isAvailable() {
|
|
18
|
+
return true; // HuggingFace free tier doesn't require a token for some models
|
|
19
|
+
}
|
|
20
|
+
async analyze(code, context) {
|
|
21
|
+
const prompt = (0, prompts_1.buildAnalysisPrompt)(code, context, 'security');
|
|
22
|
+
try {
|
|
23
|
+
const response = await this.callAPI(this.model, prompt);
|
|
24
|
+
return (0, provider_1.parseAIResponse)(response);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
try {
|
|
28
|
+
// Fallback to secondary model
|
|
29
|
+
const response = await this.callAPI(FALLBACK_MODEL, prompt);
|
|
30
|
+
return (0, provider_1.parseAIResponse)(response);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async callAPI(model, prompt) {
|
|
38
|
+
const headers = {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
};
|
|
41
|
+
if (this.token) {
|
|
42
|
+
headers['Authorization'] = `Bearer ${this.token}`;
|
|
43
|
+
}
|
|
44
|
+
const body = JSON.stringify({
|
|
45
|
+
inputs: prompt,
|
|
46
|
+
parameters: {
|
|
47
|
+
max_new_tokens: 2048,
|
|
48
|
+
temperature: 0.1,
|
|
49
|
+
return_full_text: false,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const response = await fetchWithRetry(`${HF_API_URL}/${model}`, {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
headers,
|
|
55
|
+
body,
|
|
56
|
+
});
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
throw new Error(`HuggingFace API error: ${response.status}`);
|
|
59
|
+
}
|
|
60
|
+
const data = await response.json();
|
|
61
|
+
if (Array.isArray(data) && data[0]?.generated_text) {
|
|
62
|
+
return data[0].generated_text;
|
|
63
|
+
}
|
|
64
|
+
return JSON.stringify(data);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.HuggingFaceProvider = HuggingFaceProvider;
|
|
68
|
+
async function fetchWithRetry(url, options, retries = 3, delay = 1000) {
|
|
69
|
+
for (let i = 0; i < retries; i++) {
|
|
70
|
+
try {
|
|
71
|
+
const response = await fetch(url, options);
|
|
72
|
+
// If model is loading, wait and retry
|
|
73
|
+
if (response.status === 503) {
|
|
74
|
+
const body = await response.json().catch(() => ({}));
|
|
75
|
+
const estimatedTime = body?.estimated_time || 20;
|
|
76
|
+
const waitTime = Math.min(estimatedTime * 1000, 30000);
|
|
77
|
+
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// Rate limited
|
|
81
|
+
if (response.status === 429) {
|
|
82
|
+
await new Promise(resolve => setTimeout(resolve, delay * (i + 1)));
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
return response;
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
if (i === retries - 1)
|
|
89
|
+
throw err;
|
|
90
|
+
await new Promise(resolve => setTimeout(resolve, delay * (i + 1)));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
throw new Error('Max retries exceeded');
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=huggingface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"huggingface.js","sourceRoot":"","sources":["../../src/ai/huggingface.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AIFinding } from '../core/severity';
|
|
2
|
+
import { AIProvider } from './provider';
|
|
3
|
+
export declare class OpenAIProvider implements AIProvider {
|
|
4
|
+
name: string;
|
|
5
|
+
private apiKey;
|
|
6
|
+
constructor();
|
|
7
|
+
isAvailable(): boolean;
|
|
8
|
+
analyze(code: string, context: string): Promise<AIFinding[]>;
|
|
9
|
+
private callDirectAPI;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/ai/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AAGzD,qBAAa,cAAe,YAAW,UAAU;IAC/C,IAAI,SAAY;IAChB,OAAO,CAAC,MAAM,CAAqB;;IAMnC,WAAW,IAAI,OAAO;IAIhB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YAgCpD,aAAa;CA0B5B"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenAIProvider = void 0;
|
|
4
|
+
const provider_1 = require("./provider");
|
|
5
|
+
const prompts_1 = require("./prompts");
|
|
6
|
+
class OpenAIProvider {
|
|
7
|
+
name = 'openai';
|
|
8
|
+
apiKey;
|
|
9
|
+
constructor() {
|
|
10
|
+
this.apiKey = process.env.OPENAI_API_KEY;
|
|
11
|
+
}
|
|
12
|
+
isAvailable() {
|
|
13
|
+
return !!this.apiKey;
|
|
14
|
+
}
|
|
15
|
+
async analyze(code, context) {
|
|
16
|
+
if (!this.apiKey)
|
|
17
|
+
return [];
|
|
18
|
+
const prompt = (0, prompts_1.buildAnalysisPrompt)(code, context, 'security');
|
|
19
|
+
try {
|
|
20
|
+
// Try to use the SDK if available
|
|
21
|
+
const OpenAI = require('openai');
|
|
22
|
+
const client = new OpenAI({ apiKey: this.apiKey });
|
|
23
|
+
const response = await client.chat.completions.create({
|
|
24
|
+
model: 'gpt-4o',
|
|
25
|
+
messages: [{
|
|
26
|
+
role: 'user',
|
|
27
|
+
content: prompt,
|
|
28
|
+
}],
|
|
29
|
+
temperature: 0.1,
|
|
30
|
+
max_tokens: 4096,
|
|
31
|
+
});
|
|
32
|
+
const text = response.choices[0]?.message?.content || '';
|
|
33
|
+
return (0, provider_1.parseAIResponse)(text);
|
|
34
|
+
}
|
|
35
|
+
catch (sdkError) {
|
|
36
|
+
// Fallback to direct API call
|
|
37
|
+
try {
|
|
38
|
+
return await this.callDirectAPI(prompt);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async callDirectAPI(prompt) {
|
|
46
|
+
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: {
|
|
49
|
+
'Content-Type': 'application/json',
|
|
50
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
51
|
+
},
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
model: 'gpt-4o',
|
|
54
|
+
messages: [{
|
|
55
|
+
role: 'user',
|
|
56
|
+
content: prompt,
|
|
57
|
+
}],
|
|
58
|
+
temperature: 0.1,
|
|
59
|
+
max_tokens: 4096,
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
throw new Error(`OpenAI API error: ${response.status}`);
|
|
64
|
+
}
|
|
65
|
+
const data = await response.json();
|
|
66
|
+
const text = data.choices?.[0]?.message?.content || '';
|
|
67
|
+
return (0, provider_1.parseAIResponse)(text);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.OpenAIProvider = OpenAIProvider;
|
|
71
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/ai/openai.ts"],"names":[],"mappings":";;;AACA,yCAAyD;AACzD,uCAAgD;AAEhD,MAAa,cAAc;IACzB,IAAI,GAAG,QAAQ,CAAC;IACR,MAAM,CAAqB;IAEnC;QACE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC3C,CAAC;IAED,WAAW;QACT,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,OAAe;QACzC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAA,6BAAmB,EAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAE9D,IAAI,CAAC;YACH,kCAAkC;YAClC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;YACjC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACpD,KAAK,EAAE,QAAQ;gBACf,QAAQ,EAAE,CAAC;wBACT,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE,MAAM;qBAChB,CAAC;gBACF,WAAW,EAAE,GAAG;gBAChB,UAAU,EAAE,IAAI;aACjB,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;YACzD,OAAO,IAAA,0BAAe,EAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,QAAQ,EAAE,CAAC;YAClB,8BAA8B;YAC9B,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,MAAc;QACxC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,4CAA4C,EAAE;YACzE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACzC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,QAAQ;gBACf,QAAQ,EAAE,CAAC;wBACT,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE,MAAM;qBAChB,CAAC;gBACF,WAAW,EAAE,GAAG;gBAChB,UAAU,EAAE,IAAI;aACjB,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,GAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;QACvD,OAAO,IAAA,0BAAe,EAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACF;AAtED,wCAsEC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const SECURITY_ANALYSIS_PROMPT = "You are a senior application security engineer performing a code review. Analyze the following code for security vulnerabilities.\n\nLook for:\n1. **Injection flaws** \u2014 SQL injection, command injection, XSS, LDAP injection, template injection\n2. **Authentication/Authorization bugs** \u2014 bypass conditions, privilege escalation, session issues\n3. **Cryptographic weaknesses** \u2014 weak algorithms, hardcoded keys, insecure randomness\n4. **Business logic vulnerabilities** \u2014 race conditions, TOCTOU, integer overflow, logic bypasses\n5. **Data exposure** \u2014 sensitive data in logs, responses, URLs, or error messages\n6. **Insecure configurations** \u2014 debug modes, permissive CORS, missing security headers\n7. **Novel attack vectors** \u2014 unusual patterns that could be exploited\n\nFor each vulnerability found, respond in this exact JSON format:\n{\n \"findings\": [\n {\n \"title\": \"Brief vulnerability title\",\n \"description\": \"Detailed explanation of the vulnerability and its impact\",\n \"severity\": \"critical|high|medium|low|info\",\n \"confidence\": \"high|medium|low\",\n \"line\": <line_number_or_null>,\n \"cwe\": \"CWE-XXX\",\n \"remediation\": \"How to fix the issue\"\n }\n ]\n}\n\nIf no vulnerabilities are found, return: { \"findings\": [] }\n\nBe precise and avoid false positives. Only report genuine security concerns.";
|
|
2
|
+
export declare const SECRETS_ANALYSIS_PROMPT = "You are a secrets detection specialist. Analyze the following code for hardcoded secrets, credentials, API keys, tokens, and sensitive configuration.\n\nLook for:\n- API keys (AWS, GCP, Azure, Stripe, SendGrid, Twilio, etc.)\n- Passwords and credentials\n- Private keys and certificates\n- Database connection strings with credentials\n- OAuth client secrets\n- JWT secrets\n- Encryption keys\n- Webhook URLs with tokens\n\nRespond in JSON format:\n{\n \"findings\": [\n {\n \"title\": \"Type of secret found\",\n \"description\": \"What was found and why it's a risk\",\n \"severity\": \"critical|high|medium\",\n \"confidence\": \"high|medium|low\",\n \"line\": <line_number_or_null>,\n \"cwe\": \"CWE-798\",\n \"remediation\": \"How to properly handle this secret\"\n }\n ]\n}";
|
|
3
|
+
export declare const ZERO_DAY_PROMPT = "You are an elite security researcher analyzing code for novel, zero-day class vulnerabilities that standard scanners would miss.\n\nFocus on:\n1. **Logic bugs** \u2014 Subtle flaws in business logic, authentication flows, or authorization checks\n2. **Race conditions** \u2014 Time-of-check to time-of-use bugs, concurrent access issues\n3. **Type confusion** \u2014 Unexpected type coercion leading to security bypass\n4. **Integer issues** \u2014 Overflow, underflow, truncation leading to security impacts\n5. **State management** \u2014 Inconsistent state that could be exploited\n6. **Error handling** \u2014 Errors that leak info or bypass security checks\n7. **Deserialization** \u2014 Unsafe data handling leading to code execution\n8. **Side channels** \u2014 Timing attacks, cache-based attacks\n\nOnly report findings you have HIGH confidence in. These should be genuine, exploitable issues.\n\nRespond in JSON format:\n{\n \"findings\": [\n {\n \"title\": \"Vulnerability title\",\n \"description\": \"Detailed technical explanation\",\n \"severity\": \"critical|high|medium\",\n \"confidence\": \"high|medium\",\n \"line\": <line_number_or_null>,\n \"cwe\": \"CWE-XXX\",\n \"remediation\": \"Specific fix\"\n }\n ]\n}";
|
|
4
|
+
export declare function buildAnalysisPrompt(code: string, context: string, promptType?: 'security' | 'secrets' | 'zeroday'): string;
|
|
5
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/ai/prompts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,wBAAwB,+4CA4BwC,CAAC;AAE9E,eAAO,MAAM,uBAAuB,2zBAyBlC,CAAC;AAEH,eAAO,MAAM,eAAe,8vCA2B1B,CAAC;AAEH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAE,UAAU,GAAG,SAAS,GAAG,SAAsB,GAAG,MAAM,CAatI"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZERO_DAY_PROMPT = exports.SECRETS_ANALYSIS_PROMPT = exports.SECURITY_ANALYSIS_PROMPT = void 0;
|
|
4
|
+
exports.buildAnalysisPrompt = buildAnalysisPrompt;
|
|
5
|
+
exports.SECURITY_ANALYSIS_PROMPT = `You are a senior application security engineer performing a code review. Analyze the following code for security vulnerabilities.
|
|
6
|
+
|
|
7
|
+
Look for:
|
|
8
|
+
1. **Injection flaws** — SQL injection, command injection, XSS, LDAP injection, template injection
|
|
9
|
+
2. **Authentication/Authorization bugs** — bypass conditions, privilege escalation, session issues
|
|
10
|
+
3. **Cryptographic weaknesses** — weak algorithms, hardcoded keys, insecure randomness
|
|
11
|
+
4. **Business logic vulnerabilities** — race conditions, TOCTOU, integer overflow, logic bypasses
|
|
12
|
+
5. **Data exposure** — sensitive data in logs, responses, URLs, or error messages
|
|
13
|
+
6. **Insecure configurations** — debug modes, permissive CORS, missing security headers
|
|
14
|
+
7. **Novel attack vectors** — unusual patterns that could be exploited
|
|
15
|
+
|
|
16
|
+
For each vulnerability found, respond in this exact JSON format:
|
|
17
|
+
{
|
|
18
|
+
"findings": [
|
|
19
|
+
{
|
|
20
|
+
"title": "Brief vulnerability title",
|
|
21
|
+
"description": "Detailed explanation of the vulnerability and its impact",
|
|
22
|
+
"severity": "critical|high|medium|low|info",
|
|
23
|
+
"confidence": "high|medium|low",
|
|
24
|
+
"line": <line_number_or_null>,
|
|
25
|
+
"cwe": "CWE-XXX",
|
|
26
|
+
"remediation": "How to fix the issue"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
If no vulnerabilities are found, return: { "findings": [] }
|
|
32
|
+
|
|
33
|
+
Be precise and avoid false positives. Only report genuine security concerns.`;
|
|
34
|
+
exports.SECRETS_ANALYSIS_PROMPT = `You are a secrets detection specialist. Analyze the following code for hardcoded secrets, credentials, API keys, tokens, and sensitive configuration.
|
|
35
|
+
|
|
36
|
+
Look for:
|
|
37
|
+
- API keys (AWS, GCP, Azure, Stripe, SendGrid, Twilio, etc.)
|
|
38
|
+
- Passwords and credentials
|
|
39
|
+
- Private keys and certificates
|
|
40
|
+
- Database connection strings with credentials
|
|
41
|
+
- OAuth client secrets
|
|
42
|
+
- JWT secrets
|
|
43
|
+
- Encryption keys
|
|
44
|
+
- Webhook URLs with tokens
|
|
45
|
+
|
|
46
|
+
Respond in JSON format:
|
|
47
|
+
{
|
|
48
|
+
"findings": [
|
|
49
|
+
{
|
|
50
|
+
"title": "Type of secret found",
|
|
51
|
+
"description": "What was found and why it's a risk",
|
|
52
|
+
"severity": "critical|high|medium",
|
|
53
|
+
"confidence": "high|medium|low",
|
|
54
|
+
"line": <line_number_or_null>,
|
|
55
|
+
"cwe": "CWE-798",
|
|
56
|
+
"remediation": "How to properly handle this secret"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}`;
|
|
60
|
+
exports.ZERO_DAY_PROMPT = `You are an elite security researcher analyzing code for novel, zero-day class vulnerabilities that standard scanners would miss.
|
|
61
|
+
|
|
62
|
+
Focus on:
|
|
63
|
+
1. **Logic bugs** — Subtle flaws in business logic, authentication flows, or authorization checks
|
|
64
|
+
2. **Race conditions** — Time-of-check to time-of-use bugs, concurrent access issues
|
|
65
|
+
3. **Type confusion** — Unexpected type coercion leading to security bypass
|
|
66
|
+
4. **Integer issues** — Overflow, underflow, truncation leading to security impacts
|
|
67
|
+
5. **State management** — Inconsistent state that could be exploited
|
|
68
|
+
6. **Error handling** — Errors that leak info or bypass security checks
|
|
69
|
+
7. **Deserialization** — Unsafe data handling leading to code execution
|
|
70
|
+
8. **Side channels** — Timing attacks, cache-based attacks
|
|
71
|
+
|
|
72
|
+
Only report findings you have HIGH confidence in. These should be genuine, exploitable issues.
|
|
73
|
+
|
|
74
|
+
Respond in JSON format:
|
|
75
|
+
{
|
|
76
|
+
"findings": [
|
|
77
|
+
{
|
|
78
|
+
"title": "Vulnerability title",
|
|
79
|
+
"description": "Detailed technical explanation",
|
|
80
|
+
"severity": "critical|high|medium",
|
|
81
|
+
"confidence": "high|medium",
|
|
82
|
+
"line": <line_number_or_null>,
|
|
83
|
+
"cwe": "CWE-XXX",
|
|
84
|
+
"remediation": "Specific fix"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}`;
|
|
88
|
+
function buildAnalysisPrompt(code, context, promptType = 'security') {
|
|
89
|
+
const prompt = promptType === 'secrets' ? exports.SECRETS_ANALYSIS_PROMPT
|
|
90
|
+
: promptType === 'zeroday' ? exports.ZERO_DAY_PROMPT
|
|
91
|
+
: exports.SECURITY_ANALYSIS_PROMPT;
|
|
92
|
+
return `${prompt}
|
|
93
|
+
|
|
94
|
+
Context: ${context}
|
|
95
|
+
|
|
96
|
+
Code to analyze:
|
|
97
|
+
\`\`\`
|
|
98
|
+
${code}
|
|
99
|
+
\`\`\``;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/ai/prompts.ts"],"names":[],"mappings":";;;AAsFA,kDAaC;AAnGY,QAAA,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;6EA4BqC,CAAC;AAEjE,QAAA,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;EAyBrC,CAAC;AAEU,QAAA,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2B7B,CAAC;AAEH,SAAgB,mBAAmB,CAAC,IAAY,EAAE,OAAe,EAAE,aAAiD,UAAU;IAC5H,MAAM,MAAM,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,+BAAuB;QAC/D,CAAC,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,uBAAe;YAC5C,CAAC,CAAC,gCAAwB,CAAC;IAE7B,OAAO,GAAG,MAAM;;WAEP,OAAO;;;;EAIhB,IAAI;OACC,CAAC;AACR,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AIFinding } from '../core/severity';
|
|
2
|
+
export interface AIProvider {
|
|
3
|
+
name: string;
|
|
4
|
+
analyze(code: string, context: string): Promise<AIFinding[]>;
|
|
5
|
+
isAvailable(): boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function getAvailableProvider(preferred?: string): AIProvider | null;
|
|
8
|
+
export declare function parseAIResponse(response: string): AIFinding[];
|
|
9
|
+
//# sourceMappingURL=provider.d.ts.map
|