Files
clawsec/skills/clawsec-nanoclaw/lib/risk.ts
davida-ps 073e771b73 Exploitability Context for CVE Advisories (#89)
* feat(advisories): add exploitability context for CVE advisories

* fix(ci): align exploitability workflow with signing model

* docs(skills): add patch release changelog entries

* chore(clawsec-feed): bump version to 0.0.5

* chore(clawsec-suite): bump version to 0.1.4

* fix(clawsec-nanoclaw): align exploitability handling and nanoclaw integration

* chore(clawsec-nanoclaw): bump version to 0.0.2

* refactor(scripts): share feed path and mirror sync helpers

* refactor(utils): unify cvss vector parsing flow

* refactor(clawsec-nanoclaw): centralize advisory risk evaluation

* docs(exploitability): refresh release metadata dates

* fix(review): align feed signing and advisory dedupe

* chore(clawsec-feed): bump version to 0.0.6

* chore(clawsec-nanoclaw): bump version to 0.0.3

* fix(backfill): limit signing to target feed only

* fix(review): keep skill runtime verify-only and dedupe matching

* chore(clawsec-nanoclaw): bump version to 0.0.4

* chore(skills): align versions with published tags

* feat(feed): enrich local population with exploitability analysis

* docs(exploitability): mark backfill as historical flow
2026-03-01 18:43:24 +02:00

89 lines
2.4 KiB
TypeScript

/**
* Shared advisory risk evaluation for NanoClaw host + MCP layers.
*/
export type SkillSafetyRecommendation = 'install' | 'block' | 'review';
export interface AdvisoryRiskInput {
severity?: string;
type?: string;
action?: string;
exploitability_score?: string;
}
export interface AdvisoryRiskEvaluation {
safe: boolean;
recommendation: SkillSafetyRecommendation;
reason: string;
}
export function normalizeExploitabilityScore(score: unknown): 'high' | 'medium' | 'low' | 'unknown' {
const value = String(score || '').toLowerCase().trim();
if (value === 'high' || value === 'medium' || value === 'low') {
return value;
}
return 'unknown';
}
export function evaluateAdvisoryRisk(advisories: AdvisoryRiskInput[]): AdvisoryRiskEvaluation {
if (advisories.length === 0) {
return { safe: true, recommendation: 'install', reason: 'No advisories found' };
}
const hasMalicious = advisories.some((a) => String(a.type || '').toLowerCase().includes('malicious'));
const hasRemoveAction = advisories.some((a) =>
/\b(remove|uninstall|disable|quarantine|block)\b/i.test(String(a.action || ''))
);
const hasCritical = advisories.some((a) => String(a.severity || '').toLowerCase() === 'critical');
const hasHigh = advisories.some((a) => String(a.severity || '').toLowerCase() === 'high');
const hasHighExploitability = advisories.some(
(a) => normalizeExploitabilityScore(a.exploitability_score) === 'high'
);
if (hasMalicious || hasRemoveAction) {
return {
safe: false,
recommendation: 'block',
reason: 'Malicious skill or removal recommended by ClawSec',
};
}
if (hasCritical && hasHighExploitability) {
return {
safe: false,
recommendation: 'block',
reason: 'Critical advisory with high exploitability context - do not install',
};
}
if (hasCritical) {
return {
safe: false,
recommendation: 'block',
reason: 'Critical security advisory - do not install',
};
}
if (hasHighExploitability) {
return {
safe: false,
recommendation: 'review',
reason: 'High exploitability advisory - urgent user review strongly recommended',
};
}
if (hasHigh) {
return {
safe: false,
recommendation: 'review',
reason: 'High severity advisory - user review strongly recommended',
};
}
return {
safe: false,
recommendation: 'review',
reason: 'Advisory found - review details before installing',
};
}