vaspera 2.13.0 → 2.14.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/CHANGELOG.md +33 -0
- package/dist/__tests__/antagonist-integration.test.d.ts +6 -0
- package/dist/__tests__/antagonist-integration.test.d.ts.map +1 -0
- package/dist/__tests__/antagonist-integration.test.js +239 -0
- package/dist/__tests__/antagonist-integration.test.js.map +1 -0
- package/dist/agents/antagonist/challenger.d.ts +46 -0
- package/dist/agents/antagonist/challenger.d.ts.map +1 -0
- package/dist/agents/antagonist/challenger.js +257 -0
- package/dist/agents/antagonist/challenger.js.map +1 -0
- package/dist/agents/antagonist/index.d.ts +31 -0
- package/dist/agents/antagonist/index.d.ts.map +1 -0
- package/dist/agents/antagonist/index.js +175 -0
- package/dist/agents/antagonist/index.js.map +1 -0
- package/dist/agents/antagonist/prioritizer.d.ts +27 -0
- package/dist/agents/antagonist/prioritizer.d.ts.map +1 -0
- package/dist/agents/antagonist/prioritizer.js +181 -0
- package/dist/agents/antagonist/prioritizer.js.map +1 -0
- package/dist/agents/antagonist/prompts.d.ts +12 -0
- package/dist/agents/antagonist/prompts.d.ts.map +1 -0
- package/dist/agents/antagonist/prompts.js +155 -0
- package/dist/agents/antagonist/prompts.js.map +1 -0
- package/dist/agents/antagonist/synthesizer.d.ts +34 -0
- package/dist/agents/antagonist/synthesizer.d.ts.map +1 -0
- package/dist/agents/antagonist/synthesizer.js +451 -0
- package/dist/agents/antagonist/synthesizer.js.map +1 -0
- package/dist/agents/antagonist/types.d.ts +145 -0
- package/dist/agents/antagonist/types.d.ts.map +1 -0
- package/dist/agents/antagonist/types.js +63 -0
- package/dist/agents/antagonist/types.js.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +2 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/certification/consensus.test.js +2 -0
- package/dist/certification/consensus.test.js.map +1 -1
- package/dist/certification/store.d.ts.map +1 -1
- package/dist/certification/store.js +6 -1
- package/dist/certification/store.js.map +1 -1
- package/dist/certification/types.d.ts +1 -1
- package/dist/certification/types.d.ts.map +1 -1
- package/dist/certification/types.js +2 -0
- package/dist/certification/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +164 -0
- package/dist/index.js.map +1 -1
- package/dist/sbom/provenance.test.js +2 -2
- package/dist/sbom/provenance.test.js.map +1 -1
- package/dist/sbom/signing.d.ts.map +1 -1
- package/dist/sbom/signing.js +5 -3
- package/dist/sbom/signing.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antagonist Agent
|
|
3
|
+
*
|
|
4
|
+
* A meta-analysis agent that runs AFTER all other agents complete.
|
|
5
|
+
* Synthesizes findings into attack narratives and challenges assumptions.
|
|
6
|
+
*
|
|
7
|
+
* Two modes:
|
|
8
|
+
* 1. Synthesis: "How would an attacker chain these findings?"
|
|
9
|
+
* 2. Challenger: "What did other agents miss? What assumptions are wrong?"
|
|
10
|
+
*
|
|
11
|
+
* @module agents/antagonist
|
|
12
|
+
*/
|
|
13
|
+
import type { Finding } from "../../certification/types.js";
|
|
14
|
+
import type { AntagonistInput, AntagonistConfig, AntagonistResult } from "./types.js";
|
|
15
|
+
export * from "./types.js";
|
|
16
|
+
export { synthesizeNarratives, synthesizeNarrativesDeterministic } from "./synthesizer.js";
|
|
17
|
+
export { runChallenger, runChallengerDeterministic } from "./challenger.js";
|
|
18
|
+
export { prioritizeRemediations, calculatePrioritizationMetrics } from "./prioritizer.js";
|
|
19
|
+
/**
|
|
20
|
+
* Run full antagonist analysis
|
|
21
|
+
*/
|
|
22
|
+
export declare function runAntagonistAnalysis(input: AntagonistInput, config?: Partial<AntagonistConfig>): Promise<AntagonistResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Quick antagonist check for a single finding
|
|
25
|
+
*/
|
|
26
|
+
export declare function quickAntagonistCheck(finding: Finding, relatedFindings: Finding[], config?: Partial<AntagonistConfig>): Promise<{
|
|
27
|
+
inAttackPath: boolean;
|
|
28
|
+
chainPotential: string[];
|
|
29
|
+
challengeRisk: "high" | "medium" | "low";
|
|
30
|
+
}>;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agents/antagonist/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAa,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAKjB,MAAM,YAAY,CAAC;AAOpB,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,iCAAiC,EAAE,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAE1F;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,eAAe,EACtB,MAAM,GAAE,OAAO,CAAC,gBAAgB,CAAM,GACrC,OAAO,CAAC,gBAAgB,CAAC,CA2G3B;AA2DD;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,OAAO,EAAE,EAC1B,MAAM,GAAE,OAAO,CAAC,gBAAgB,CAAM,GACrC,OAAO,CAAC;IACT,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CAC1C,CAAC,CA+BD"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antagonist Agent
|
|
3
|
+
*
|
|
4
|
+
* A meta-analysis agent that runs AFTER all other agents complete.
|
|
5
|
+
* Synthesizes findings into attack narratives and challenges assumptions.
|
|
6
|
+
*
|
|
7
|
+
* Two modes:
|
|
8
|
+
* 1. Synthesis: "How would an attacker chain these findings?"
|
|
9
|
+
* 2. Challenger: "What did other agents miss? What assumptions are wrong?"
|
|
10
|
+
*
|
|
11
|
+
* @module agents/antagonist
|
|
12
|
+
*/
|
|
13
|
+
import { DEFAULT_ANTAGONIST_CONFIG } from "./types.js";
|
|
14
|
+
import { synthesizeNarratives } from "./synthesizer.js";
|
|
15
|
+
import { runChallenger } from "./challenger.js";
|
|
16
|
+
import { prioritizeRemediations } from "./prioritizer.js";
|
|
17
|
+
import { logger } from "../../logger.js";
|
|
18
|
+
export * from "./types.js";
|
|
19
|
+
export { synthesizeNarratives, synthesizeNarrativesDeterministic } from "./synthesizer.js";
|
|
20
|
+
export { runChallenger, runChallengerDeterministic } from "./challenger.js";
|
|
21
|
+
export { prioritizeRemediations, calculatePrioritizationMetrics } from "./prioritizer.js";
|
|
22
|
+
/**
|
|
23
|
+
* Run full antagonist analysis
|
|
24
|
+
*/
|
|
25
|
+
export async function runAntagonistAnalysis(input, config = {}) {
|
|
26
|
+
const startTime = Date.now();
|
|
27
|
+
const fullConfig = { ...DEFAULT_ANTAGONIST_CONFIG, ...config };
|
|
28
|
+
logger.info("antagonist.analysis_started", {
|
|
29
|
+
certificationId: input.certificationId,
|
|
30
|
+
findingsCount: input.findings.length,
|
|
31
|
+
chainsCount: input.exploitChains.length,
|
|
32
|
+
mode: fullConfig.mode,
|
|
33
|
+
});
|
|
34
|
+
const analysisId = `ant-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
35
|
+
let narratives = [];
|
|
36
|
+
let assessments = [];
|
|
37
|
+
let gapAnalysis = {
|
|
38
|
+
untestedAttackVectors: [],
|
|
39
|
+
missingControls: [],
|
|
40
|
+
blindSpots: [],
|
|
41
|
+
recommendations: [],
|
|
42
|
+
coverageScore: 100,
|
|
43
|
+
};
|
|
44
|
+
let prioritization = [];
|
|
45
|
+
let totalTokens = 0;
|
|
46
|
+
try {
|
|
47
|
+
if (fullConfig.mode === "synthesis" || fullConfig.mode === "both") {
|
|
48
|
+
const synthesisResult = await synthesizeNarratives(input.findings, input.exploitChains, input.exfilPaths, fullConfig);
|
|
49
|
+
narratives = synthesisResult.narratives;
|
|
50
|
+
totalTokens += synthesisResult.tokensUsed;
|
|
51
|
+
logger.debug("antagonist.synthesis_complete", {
|
|
52
|
+
narrativesFound: narratives.length,
|
|
53
|
+
tokensUsed: synthesisResult.tokensUsed,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (fullConfig.mode === "challenger" || fullConfig.mode === "both") {
|
|
57
|
+
const challengerResult = await runChallenger(input.findings, input.agentSummaries, fullConfig);
|
|
58
|
+
assessments = challengerResult.assessments;
|
|
59
|
+
gapAnalysis = challengerResult.gapAnalysis;
|
|
60
|
+
totalTokens += challengerResult.tokensUsed;
|
|
61
|
+
logger.debug("antagonist.challenger_complete", {
|
|
62
|
+
assessmentsFound: assessments.length,
|
|
63
|
+
coverageScore: gapAnalysis.coverageScore,
|
|
64
|
+
tokensUsed: challengerResult.tokensUsed,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (fullConfig.includePrioritization && narratives.length > 0) {
|
|
68
|
+
prioritization = prioritizeRemediations(input.findings, narratives);
|
|
69
|
+
logger.debug("antagonist.prioritization_complete", {
|
|
70
|
+
prioritizedFindings: prioritization.length,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const summary = generateSummary(narratives, assessments, gapAnalysis, prioritization);
|
|
74
|
+
const duration = Date.now() - startTime;
|
|
75
|
+
logger.info("antagonist.analysis_complete", {
|
|
76
|
+
analysisId,
|
|
77
|
+
narratives: narratives.length,
|
|
78
|
+
assessments: assessments.length,
|
|
79
|
+
coverageScore: gapAnalysis.coverageScore,
|
|
80
|
+
duration,
|
|
81
|
+
tokensUsed: totalTokens,
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
success: true,
|
|
85
|
+
analysisId,
|
|
86
|
+
attackNarratives: narratives,
|
|
87
|
+
challengerAssessments: assessments,
|
|
88
|
+
prioritization,
|
|
89
|
+
gapAnalysis,
|
|
90
|
+
summary,
|
|
91
|
+
duration,
|
|
92
|
+
tokensUsed: totalTokens,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
97
|
+
logger.error("antagonist.analysis_failed", { error: errorMessage });
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
analysisId,
|
|
101
|
+
attackNarratives: narratives,
|
|
102
|
+
challengerAssessments: assessments,
|
|
103
|
+
prioritization,
|
|
104
|
+
gapAnalysis,
|
|
105
|
+
summary: `Analysis failed: ${errorMessage}`,
|
|
106
|
+
duration: Date.now() - startTime,
|
|
107
|
+
tokensUsed: totalTokens,
|
|
108
|
+
error: errorMessage,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Generate summary text from analysis results
|
|
114
|
+
*/
|
|
115
|
+
function generateSummary(narratives, assessments, gapAnalysis, prioritization) {
|
|
116
|
+
const lines = [];
|
|
117
|
+
if (narratives.length > 0) {
|
|
118
|
+
const highLikelihood = narratives.filter((n) => n.likelihood === "high").length;
|
|
119
|
+
const criticalImpact = narratives.filter((n) => n.impact.toLowerCase().includes("complete") || n.impact.toLowerCase().includes("critical")).length;
|
|
120
|
+
lines.push(`Identified ${narratives.length} attack narrative(s): ${highLikelihood} high-likelihood, ${criticalImpact} with critical impact.`);
|
|
121
|
+
const topNarrative = narratives[0];
|
|
122
|
+
if (topNarrative) {
|
|
123
|
+
lines.push(`Most likely attack: "${topNarrative.name}" (${topNarrative.likelihood} likelihood, ${topNarrative.difficulty} difficulty).`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
lines.push("No clear attack narratives identified from current findings.");
|
|
128
|
+
}
|
|
129
|
+
if (assessments.length > 0) {
|
|
130
|
+
const fpLikely = assessments.filter((a) => a.type === "false_positive_likely").length;
|
|
131
|
+
const missedChecks = assessments.filter((a) => a.type === "missed_check").length;
|
|
132
|
+
if (fpLikely > 0) {
|
|
133
|
+
lines.push(`Flagged ${fpLikely} potential false positive(s) for review.`);
|
|
134
|
+
}
|
|
135
|
+
if (missedChecks > 0) {
|
|
136
|
+
lines.push(`Identified ${missedChecks} uncovered attack vector(s).`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (gapAnalysis.coverageScore < 80) {
|
|
140
|
+
lines.push(`Coverage score: ${gapAnalysis.coverageScore}%. Missing: ${gapAnalysis.untestedAttackVectors.slice(0, 3).join(", ")}.`);
|
|
141
|
+
}
|
|
142
|
+
if (prioritization.length > 0) {
|
|
143
|
+
const topThree = prioritization.slice(0, 3).map((p) => p.findingId);
|
|
144
|
+
lines.push(`Priority fixes: ${topThree.join(", ")}.`);
|
|
145
|
+
}
|
|
146
|
+
return lines.join(" ");
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Quick antagonist check for a single finding
|
|
150
|
+
*/
|
|
151
|
+
export async function quickAntagonistCheck(finding, relatedFindings, config = {}) {
|
|
152
|
+
const fullConfig = {
|
|
153
|
+
...DEFAULT_ANTAGONIST_CONFIG,
|
|
154
|
+
...config,
|
|
155
|
+
useLlm: false,
|
|
156
|
+
maxNarratives: 3,
|
|
157
|
+
};
|
|
158
|
+
const { narratives } = await synthesizeNarratives([finding, ...relatedFindings], [], [], fullConfig);
|
|
159
|
+
const inAttackPath = narratives.some((n) => n.findingIds.includes(finding.id));
|
|
160
|
+
const chainPotential = narratives
|
|
161
|
+
.filter((n) => n.findingIds.includes(finding.id))
|
|
162
|
+
.flatMap((n) => n.findingIds)
|
|
163
|
+
.filter((id) => id !== finding.id);
|
|
164
|
+
let challengeRisk = "low";
|
|
165
|
+
if (finding.confidence < 50)
|
|
166
|
+
challengeRisk = "high";
|
|
167
|
+
else if (finding.confidence < 70 || finding.file?.includes("test"))
|
|
168
|
+
challengeRisk = "medium";
|
|
169
|
+
return {
|
|
170
|
+
inAttackPath,
|
|
171
|
+
chainPotential: [...new Set(chainPotential)],
|
|
172
|
+
challengeRisk,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/agents/antagonist/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antagonist Remediation Prioritizer
|
|
3
|
+
*
|
|
4
|
+
* Prioritizes findings based on:
|
|
5
|
+
* 1. Attack surface reduction (blocks most narratives)
|
|
6
|
+
* 2. Bottleneck findings (appear in multiple chains)
|
|
7
|
+
* 3. Effort vs. impact trade-offs
|
|
8
|
+
*
|
|
9
|
+
* @module agents/antagonist/prioritizer
|
|
10
|
+
*/
|
|
11
|
+
import type { Finding } from "../../certification/types.js";
|
|
12
|
+
import type { AttackNarrative, PrioritizedRemediation } from "./types.js";
|
|
13
|
+
/**
|
|
14
|
+
* Generate prioritized remediation list
|
|
15
|
+
*/
|
|
16
|
+
export declare function prioritizeRemediations(findings: Finding[], narratives: AttackNarrative[]): PrioritizedRemediation[];
|
|
17
|
+
/**
|
|
18
|
+
* Calculate overall prioritization metrics
|
|
19
|
+
*/
|
|
20
|
+
export declare function calculatePrioritizationMetrics(prioritizations: PrioritizedRemediation[], narratives: AttackNarrative[]): {
|
|
21
|
+
totalFindings: number;
|
|
22
|
+
criticalPathFindings: number;
|
|
23
|
+
quickWins: number;
|
|
24
|
+
estimatedEffort: string;
|
|
25
|
+
topThreeImpact: string;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=prioritizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prioritizer.d.ts","sourceRoot":"","sources":["../../../src/agents/antagonist/prioritizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAY,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAkF1E;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,OAAO,EAAE,EACnB,UAAU,EAAE,eAAe,EAAE,GAC5B,sBAAsB,EAAE,CAsE1B;AAuCD;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,eAAe,EAAE,sBAAsB,EAAE,EACzC,UAAU,EAAE,eAAe,EAAE,GAC5B;IACD,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB,CA+BA"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antagonist Remediation Prioritizer
|
|
3
|
+
*
|
|
4
|
+
* Prioritizes findings based on:
|
|
5
|
+
* 1. Attack surface reduction (blocks most narratives)
|
|
6
|
+
* 2. Bottleneck findings (appear in multiple chains)
|
|
7
|
+
* 3. Effort vs. impact trade-offs
|
|
8
|
+
*
|
|
9
|
+
* @module agents/antagonist/prioritizer
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Effort estimation based on finding category
|
|
13
|
+
*/
|
|
14
|
+
const CATEGORY_EFFORT = {
|
|
15
|
+
"hardcoded-secret": "low",
|
|
16
|
+
xss: "low",
|
|
17
|
+
"path-traversal": "low",
|
|
18
|
+
"sql-injection": "medium",
|
|
19
|
+
"auth-bypass": "medium",
|
|
20
|
+
"broken-access-control": "medium",
|
|
21
|
+
"command-injection": "medium",
|
|
22
|
+
"code-injection": "high",
|
|
23
|
+
"prompt-injection": "high",
|
|
24
|
+
"excessive-agency": "high",
|
|
25
|
+
"logic-flaw": "high",
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Impact estimation based on severity and narrative involvement
|
|
29
|
+
*/
|
|
30
|
+
function calculateImpact(finding, narrativeCount) {
|
|
31
|
+
const severityScore = {
|
|
32
|
+
critical: 5,
|
|
33
|
+
high: 4,
|
|
34
|
+
medium: 3,
|
|
35
|
+
low: 2,
|
|
36
|
+
info: 1,
|
|
37
|
+
};
|
|
38
|
+
const score = severityScore[finding.severity] + narrativeCount;
|
|
39
|
+
if (score >= 7)
|
|
40
|
+
return "high";
|
|
41
|
+
if (score >= 4)
|
|
42
|
+
return "medium";
|
|
43
|
+
return "low";
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Count how many narratives each finding appears in
|
|
47
|
+
*/
|
|
48
|
+
function countNarrativeAppearances(findings, narratives) {
|
|
49
|
+
const appearances = new Map();
|
|
50
|
+
for (const finding of findings) {
|
|
51
|
+
appearances.set(finding.id, []);
|
|
52
|
+
}
|
|
53
|
+
for (const narrative of narratives) {
|
|
54
|
+
for (const findingId of narrative.findingIds) {
|
|
55
|
+
const existing = appearances.get(findingId) || [];
|
|
56
|
+
existing.push(narrative.id);
|
|
57
|
+
appearances.set(findingId, existing);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return appearances;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Calculate attack surface reduction if finding is fixed
|
|
64
|
+
*/
|
|
65
|
+
function calculateAttackSurfaceReduction(findingId, narratives) {
|
|
66
|
+
const totalNarratives = narratives.length;
|
|
67
|
+
if (totalNarratives === 0)
|
|
68
|
+
return 0;
|
|
69
|
+
const blockedNarratives = narratives.filter((n) => n.findingIds.includes(findingId)).length;
|
|
70
|
+
return Math.round((blockedNarratives / totalNarratives) * 100);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Generate prioritized remediation list
|
|
74
|
+
*/
|
|
75
|
+
export function prioritizeRemediations(findings, narratives) {
|
|
76
|
+
const appearances = countNarrativeAppearances(findings, narratives);
|
|
77
|
+
const prioritizations = [];
|
|
78
|
+
const findingsWithNarratives = findings.filter((f) => {
|
|
79
|
+
const narrativeIds = appearances.get(f.id) || [];
|
|
80
|
+
return narrativeIds.length > 0;
|
|
81
|
+
});
|
|
82
|
+
const scored = findingsWithNarratives.map((finding) => {
|
|
83
|
+
const narrativeIds = appearances.get(finding.id) || [];
|
|
84
|
+
const attackSurfaceReduction = calculateAttackSurfaceReduction(finding.id, narratives);
|
|
85
|
+
const severityScore = {
|
|
86
|
+
critical: 100,
|
|
87
|
+
high: 75,
|
|
88
|
+
medium: 50,
|
|
89
|
+
low: 25,
|
|
90
|
+
info: 10,
|
|
91
|
+
};
|
|
92
|
+
const effortPenalty = {
|
|
93
|
+
low: 0,
|
|
94
|
+
medium: 15,
|
|
95
|
+
high: 30,
|
|
96
|
+
};
|
|
97
|
+
const effort = CATEGORY_EFFORT[finding.category] || "medium";
|
|
98
|
+
const score = severityScore[finding.severity] +
|
|
99
|
+
attackSurfaceReduction +
|
|
100
|
+
narrativeIds.length * 10 -
|
|
101
|
+
effortPenalty[effort];
|
|
102
|
+
return { finding, narrativeIds, score, effort };
|
|
103
|
+
});
|
|
104
|
+
scored.sort((a, b) => b.score - a.score);
|
|
105
|
+
for (let i = 0; i < scored.length; i++) {
|
|
106
|
+
const { finding, narrativeIds, effort } = scored[i];
|
|
107
|
+
prioritizations.push({
|
|
108
|
+
order: i + 1,
|
|
109
|
+
findingId: finding.id,
|
|
110
|
+
reason: generateReason(finding, narrativeIds.length, narratives),
|
|
111
|
+
blocksNarratives: narrativeIds,
|
|
112
|
+
effort,
|
|
113
|
+
impact: calculateImpact(finding, narrativeIds.length),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
for (const finding of findings) {
|
|
117
|
+
const narrativeIds = appearances.get(finding.id) || [];
|
|
118
|
+
if (narrativeIds.length === 0 && finding.severity !== "info") {
|
|
119
|
+
prioritizations.push({
|
|
120
|
+
order: prioritizations.length + 1,
|
|
121
|
+
findingId: finding.id,
|
|
122
|
+
reason: `Standalone ${finding.severity} finding not in attack chains`,
|
|
123
|
+
blocksNarratives: [],
|
|
124
|
+
effort: CATEGORY_EFFORT[finding.category] || "medium",
|
|
125
|
+
impact: calculateImpact(finding, 0),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return prioritizations;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Generate reason for prioritization
|
|
133
|
+
*/
|
|
134
|
+
function generateReason(finding, narrativeCount, narratives) {
|
|
135
|
+
const reasons = [];
|
|
136
|
+
if (finding.severity === "critical") {
|
|
137
|
+
reasons.push("Critical severity requires immediate attention");
|
|
138
|
+
}
|
|
139
|
+
if (narrativeCount > 2) {
|
|
140
|
+
reasons.push(`Bottleneck: appears in ${narrativeCount} attack paths`);
|
|
141
|
+
}
|
|
142
|
+
else if (narrativeCount > 0) {
|
|
143
|
+
reasons.push(`Part of ${narrativeCount} attack path(s)`);
|
|
144
|
+
}
|
|
145
|
+
const isEntryPoint = narratives.some((n) => n.entryPoint === finding.id);
|
|
146
|
+
if (isEntryPoint) {
|
|
147
|
+
reasons.push("Entry point for attack chain");
|
|
148
|
+
}
|
|
149
|
+
const effort = CATEGORY_EFFORT[finding.category] || "medium";
|
|
150
|
+
if (effort === "low") {
|
|
151
|
+
reasons.push("Quick fix");
|
|
152
|
+
}
|
|
153
|
+
if (reasons.length === 0) {
|
|
154
|
+
reasons.push(`${finding.severity} ${finding.category} vulnerability`);
|
|
155
|
+
}
|
|
156
|
+
return reasons.join(". ");
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Calculate overall prioritization metrics
|
|
160
|
+
*/
|
|
161
|
+
export function calculatePrioritizationMetrics(prioritizations, narratives) {
|
|
162
|
+
const criticalPathFindings = prioritizations.filter((p) => p.blocksNarratives.length > 0).length;
|
|
163
|
+
const quickWins = prioritizations.filter((p) => p.effort === "low" && p.impact !== "low").length;
|
|
164
|
+
const effortHours = {
|
|
165
|
+
low: 1,
|
|
166
|
+
medium: 4,
|
|
167
|
+
high: 8,
|
|
168
|
+
};
|
|
169
|
+
const totalHours = prioritizations.reduce((sum, p) => sum + effortHours[p.effort], 0);
|
|
170
|
+
const topThree = prioritizations.slice(0, 3);
|
|
171
|
+
const topThreeBlocks = new Set(topThree.flatMap((p) => p.blocksNarratives));
|
|
172
|
+
const topThreeImpact = `Fixing top 3 blocks ${topThreeBlocks.size}/${narratives.length} attack paths`;
|
|
173
|
+
return {
|
|
174
|
+
totalFindings: prioritizations.length,
|
|
175
|
+
criticalPathFindings,
|
|
176
|
+
quickWins,
|
|
177
|
+
estimatedEffort: `${totalHours} hours`,
|
|
178
|
+
topThreeImpact,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=prioritizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prioritizer.js","sourceRoot":"","sources":["../../../src/agents/antagonist/prioritizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antagonist Agent LLM Prompts
|
|
3
|
+
*
|
|
4
|
+
* @module agents/antagonist/prompts
|
|
5
|
+
*/
|
|
6
|
+
export declare const SYNTHESIS_SYSTEM_PROMPT = "You are a senior red team operator analyzing security findings from multiple tools and agents.\n\nYour task is to synthesize individual findings into realistic attack narratives. Think like an attacker:\n- What would be the entry point?\n- How would findings chain together?\n- What is the ultimate goal (data exfil, persistence, privilege escalation)?\n- What makes this attack likely to succeed?\n\nFor each narrative, map to MITRE ATT&CK kill chain phases:\n1. Reconnaissance - Gathering information\n2. Resource Development - Establishing resources\n3. Initial Access - Gaining foothold\n4. Execution - Running malicious code\n5. Persistence - Maintaining access\n6. Privilege Escalation - Getting higher permissions\n7. Defense Evasion - Avoiding detection\n8. Credential Access - Stealing credentials\n9. Discovery - Learning the environment\n10. Lateral Movement - Moving through network\n11. Collection - Gathering data\n12. Command and Control - Communicating with implants\n13. Exfiltration - Stealing data\n14. Impact - Disruption or destruction\n\nOutput JSON with this structure:\n{\n \"narratives\": [\n {\n \"name\": \"Attack name\",\n \"entryPoint\": \"First finding ID\",\n \"targetAsset\": \"What attacker wants\",\n \"impact\": \"Business impact\",\n \"difficulty\": \"trivial|easy|moderate|hard|expert\",\n \"likelihood\": \"high|medium|low\",\n \"findingIds\": [\"finding-1\", \"finding-2\"],\n \"phases\": [\n {\"phase\": \"initial-access\", \"findingId\": \"...\", \"description\": \"...\", \"technique\": \"T1190\"}\n ],\n \"mitreTechniques\": [\"T1190\", \"T1059\"],\n \"narrative\": \"Detailed attack story...\",\n \"confidence\": 85\n }\n ]\n}";
|
|
7
|
+
export declare const CHALLENGER_SYSTEM_PROMPT = "You are a skeptical security reviewer challenging the findings from other agents.\n\nYour job is to identify:\n1. FALSE POSITIVES - findings that are likely not exploitable in context\n2. MISSING CONTEXT - findings that need more evidence\n3. WRONG SEVERITY - findings that should be higher or lower severity\n4. WRONG ASSUMPTIONS - findings based on incorrect assumptions\n5. BLIND SPOTS - what attacks were NOT checked\n\nBe constructive but rigorous. If a finding lacks evidence of real exploitability, challenge it.\nIf an obvious attack vector was missed, flag it.\n\nOutput JSON with this structure:\n{\n \"challenges\": [\n {\n \"type\": \"false_positive_likely|missing_context|wrong_severity|wrong_assumption|missed_check\",\n \"targetAgent\": \"security|reliability|adversary|etc\",\n \"targetFindingId\": \"finding-id or null\",\n \"challenge\": \"What is wrong\",\n \"evidence\": \"Why you think this\",\n \"suggestedAction\": \"What should be done\",\n \"severity\": \"high|medium|low\",\n \"confidence\": 75\n }\n ],\n \"blindSpots\": [\"Attack vector not tested\", \"...\"]\n}";
|
|
8
|
+
export declare const PRIORITIZATION_SYSTEM_PROMPT = "You are a security architect prioritizing remediation efforts.\n\nGiven attack narratives and findings, determine the optimal fix order that:\n1. Blocks the most attack paths with the least effort\n2. Addresses bottleneck findings (appear in multiple narratives)\n3. Considers fix complexity vs. security impact\n\nOutput JSON with this structure:\n{\n \"prioritization\": [\n {\n \"order\": 1,\n \"findingId\": \"finding-id\",\n \"reason\": \"Why fix this first\",\n \"blocksNarratives\": [\"narrative-1\", \"narrative-2\"],\n \"effort\": \"low|medium|high\",\n \"impact\": \"low|medium|high\"\n }\n ]\n}";
|
|
9
|
+
export declare function buildSynthesisPrompt(findings: string, chains: string, paths: string): string;
|
|
10
|
+
export declare function buildChallengerPrompt(findings: string, agentSummaries: string, vectors: string): string;
|
|
11
|
+
export declare function buildPrioritizationPrompt(narratives: string, findings: string): string;
|
|
12
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/agents/antagonist/prompts.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,uBAAuB,stDA2ClC,CAAC;AAEH,eAAO,MAAM,wBAAwB,wnCA2BnC,CAAC;AAEH,eAAO,MAAM,4BAA4B,woBAmBvC,CAAC;AAEH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAmB5F;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GACd,MAAM,CAoBR;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAeR"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antagonist Agent LLM Prompts
|
|
3
|
+
*
|
|
4
|
+
* @module agents/antagonist/prompts
|
|
5
|
+
*/
|
|
6
|
+
export const SYNTHESIS_SYSTEM_PROMPT = `You are a senior red team operator analyzing security findings from multiple tools and agents.
|
|
7
|
+
|
|
8
|
+
Your task is to synthesize individual findings into realistic attack narratives. Think like an attacker:
|
|
9
|
+
- What would be the entry point?
|
|
10
|
+
- How would findings chain together?
|
|
11
|
+
- What is the ultimate goal (data exfil, persistence, privilege escalation)?
|
|
12
|
+
- What makes this attack likely to succeed?
|
|
13
|
+
|
|
14
|
+
For each narrative, map to MITRE ATT&CK kill chain phases:
|
|
15
|
+
1. Reconnaissance - Gathering information
|
|
16
|
+
2. Resource Development - Establishing resources
|
|
17
|
+
3. Initial Access - Gaining foothold
|
|
18
|
+
4. Execution - Running malicious code
|
|
19
|
+
5. Persistence - Maintaining access
|
|
20
|
+
6. Privilege Escalation - Getting higher permissions
|
|
21
|
+
7. Defense Evasion - Avoiding detection
|
|
22
|
+
8. Credential Access - Stealing credentials
|
|
23
|
+
9. Discovery - Learning the environment
|
|
24
|
+
10. Lateral Movement - Moving through network
|
|
25
|
+
11. Collection - Gathering data
|
|
26
|
+
12. Command and Control - Communicating with implants
|
|
27
|
+
13. Exfiltration - Stealing data
|
|
28
|
+
14. Impact - Disruption or destruction
|
|
29
|
+
|
|
30
|
+
Output JSON with this structure:
|
|
31
|
+
{
|
|
32
|
+
"narratives": [
|
|
33
|
+
{
|
|
34
|
+
"name": "Attack name",
|
|
35
|
+
"entryPoint": "First finding ID",
|
|
36
|
+
"targetAsset": "What attacker wants",
|
|
37
|
+
"impact": "Business impact",
|
|
38
|
+
"difficulty": "trivial|easy|moderate|hard|expert",
|
|
39
|
+
"likelihood": "high|medium|low",
|
|
40
|
+
"findingIds": ["finding-1", "finding-2"],
|
|
41
|
+
"phases": [
|
|
42
|
+
{"phase": "initial-access", "findingId": "...", "description": "...", "technique": "T1190"}
|
|
43
|
+
],
|
|
44
|
+
"mitreTechniques": ["T1190", "T1059"],
|
|
45
|
+
"narrative": "Detailed attack story...",
|
|
46
|
+
"confidence": 85
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}`;
|
|
50
|
+
export const CHALLENGER_SYSTEM_PROMPT = `You are a skeptical security reviewer challenging the findings from other agents.
|
|
51
|
+
|
|
52
|
+
Your job is to identify:
|
|
53
|
+
1. FALSE POSITIVES - findings that are likely not exploitable in context
|
|
54
|
+
2. MISSING CONTEXT - findings that need more evidence
|
|
55
|
+
3. WRONG SEVERITY - findings that should be higher or lower severity
|
|
56
|
+
4. WRONG ASSUMPTIONS - findings based on incorrect assumptions
|
|
57
|
+
5. BLIND SPOTS - what attacks were NOT checked
|
|
58
|
+
|
|
59
|
+
Be constructive but rigorous. If a finding lacks evidence of real exploitability, challenge it.
|
|
60
|
+
If an obvious attack vector was missed, flag it.
|
|
61
|
+
|
|
62
|
+
Output JSON with this structure:
|
|
63
|
+
{
|
|
64
|
+
"challenges": [
|
|
65
|
+
{
|
|
66
|
+
"type": "false_positive_likely|missing_context|wrong_severity|wrong_assumption|missed_check",
|
|
67
|
+
"targetAgent": "security|reliability|adversary|etc",
|
|
68
|
+
"targetFindingId": "finding-id or null",
|
|
69
|
+
"challenge": "What is wrong",
|
|
70
|
+
"evidence": "Why you think this",
|
|
71
|
+
"suggestedAction": "What should be done",
|
|
72
|
+
"severity": "high|medium|low",
|
|
73
|
+
"confidence": 75
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"blindSpots": ["Attack vector not tested", "..."]
|
|
77
|
+
}`;
|
|
78
|
+
export const PRIORITIZATION_SYSTEM_PROMPT = `You are a security architect prioritizing remediation efforts.
|
|
79
|
+
|
|
80
|
+
Given attack narratives and findings, determine the optimal fix order that:
|
|
81
|
+
1. Blocks the most attack paths with the least effort
|
|
82
|
+
2. Addresses bottleneck findings (appear in multiple narratives)
|
|
83
|
+
3. Considers fix complexity vs. security impact
|
|
84
|
+
|
|
85
|
+
Output JSON with this structure:
|
|
86
|
+
{
|
|
87
|
+
"prioritization": [
|
|
88
|
+
{
|
|
89
|
+
"order": 1,
|
|
90
|
+
"findingId": "finding-id",
|
|
91
|
+
"reason": "Why fix this first",
|
|
92
|
+
"blocksNarratives": ["narrative-1", "narrative-2"],
|
|
93
|
+
"effort": "low|medium|high",
|
|
94
|
+
"impact": "low|medium|high"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}`;
|
|
98
|
+
export function buildSynthesisPrompt(findings, chains, paths) {
|
|
99
|
+
return `Analyze these security findings and synthesize them into attack narratives:
|
|
100
|
+
|
|
101
|
+
## Findings from All Agents
|
|
102
|
+
${findings}
|
|
103
|
+
|
|
104
|
+
## Existing Exploit Chains Detected
|
|
105
|
+
${chains}
|
|
106
|
+
|
|
107
|
+
## Data Exfiltration Paths
|
|
108
|
+
${paths}
|
|
109
|
+
|
|
110
|
+
Based on this data, identify realistic attack scenarios an attacker would pursue. Focus on:
|
|
111
|
+
- Which findings can be chained together
|
|
112
|
+
- What the attacker's likely goals would be
|
|
113
|
+
- How difficult each attack would be
|
|
114
|
+
- What MITRE ATT&CK techniques apply
|
|
115
|
+
|
|
116
|
+
Generate 3-5 attack narratives, prioritized by likelihood and impact.`;
|
|
117
|
+
}
|
|
118
|
+
export function buildChallengerPrompt(findings, agentSummaries, vectors) {
|
|
119
|
+
return `Review these security findings and challenge any that seem questionable:
|
|
120
|
+
|
|
121
|
+
## Findings to Review
|
|
122
|
+
${findings}
|
|
123
|
+
|
|
124
|
+
## Agent Coverage Summary
|
|
125
|
+
${agentSummaries}
|
|
126
|
+
|
|
127
|
+
## Attack Vectors to Check
|
|
128
|
+
${vectors}
|
|
129
|
+
|
|
130
|
+
Identify:
|
|
131
|
+
1. Findings that are likely false positives (not exploitable in this context)
|
|
132
|
+
2. Findings with insufficient evidence
|
|
133
|
+
3. Findings with wrong severity (over or underrated)
|
|
134
|
+
4. Missing checks - attack vectors that weren't tested
|
|
135
|
+
5. Wrong assumptions made by agents
|
|
136
|
+
|
|
137
|
+
Be specific and cite evidence for each challenge.`;
|
|
138
|
+
}
|
|
139
|
+
export function buildPrioritizationPrompt(narratives, findings) {
|
|
140
|
+
return `Given these attack narratives and findings, create an optimal remediation plan:
|
|
141
|
+
|
|
142
|
+
## Attack Narratives
|
|
143
|
+
${narratives}
|
|
144
|
+
|
|
145
|
+
## All Findings
|
|
146
|
+
${findings}
|
|
147
|
+
|
|
148
|
+
Prioritize fixes to:
|
|
149
|
+
1. Block the maximum number of attack paths
|
|
150
|
+
2. Fix bottleneck findings that appear in multiple narratives first
|
|
151
|
+
3. Balance effort vs. impact
|
|
152
|
+
|
|
153
|
+
Output an ordered list of findings to fix, with justification for each.`;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/agents/antagonist/prompts.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2CrC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BtC,CAAC;AAEH,MAAM,CAAC,MAAM,4BAA4B,GAAG;;;;;;;;;;;;;;;;;;;EAmB1C,CAAC;AAEH,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,MAAc,EAAE,KAAa;IAClF,OAAO;;;EAGP,QAAQ;;;EAGR,MAAM;;;EAGN,KAAK;;;;;;;;sEAQ+D,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,cAAsB,EACtB,OAAe;IAEf,OAAO;;;EAGP,QAAQ;;;EAGR,cAAc;;;EAGd,OAAO;;;;;;;;;kDASyC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,UAAkB,EAClB,QAAgB;IAEhB,OAAO;;;EAGP,UAAU;;;EAGV,QAAQ;;;;;;;wEAO8D,CAAC;AACzE,CAAC"}
|