@clear-capabilities/agentic-security-scanner 0.78.0 → 0.80.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.
Files changed (126) hide show
  1. package/bin/.agentic-security/findings.json +16 -16
  2. package/bin/.agentic-security/last-scan.json +16 -16
  3. package/bin/.agentic-security/last-scan.json.sig +1 -1
  4. package/bin/.agentic-security/scan-history.json +51 -0
  5. package/bin/.agentic-security/streak.json +5 -5
  6. package/bin/agentic-security.js +22 -7
  7. package/dist/178.index.js +1 -1
  8. package/dist/333.index.js +283 -0
  9. package/dist/384.index.js +1 -1
  10. package/dist/476.index.js +5 -5
  11. package/dist/637.index.js +1 -1
  12. package/dist/700.index.js +138 -0
  13. package/dist/718.index.js +53 -0
  14. package/dist/838.index.js +1 -1
  15. package/dist/985.index.js +95 -1
  16. package/dist/agentic-security.mjs +83 -83
  17. package/dist/agentic-security.mjs.sha256 +1 -1
  18. package/package.json +6 -4
  19. package/src/.agentic-security/findings.json +29799 -7803
  20. package/src/.agentic-security/last-scan.json +29799 -7803
  21. package/src/.agentic-security/last-scan.json.sig +1 -1
  22. package/src/.agentic-security/scan-history.json +5119 -2611
  23. package/src/.agentic-security/streak.json +6 -6
  24. package/src/dataflow/.agentic-security/findings.json +2879 -308
  25. package/src/dataflow/.agentic-security/last-scan.json +2879 -308
  26. package/src/dataflow/.agentic-security/last-scan.json.sig +1 -1
  27. package/src/dataflow/.agentic-security/scan-history.json +68 -520
  28. package/src/dataflow/.agentic-security/streak.json +6 -7
  29. package/src/dataflow/cross-service-taint.js +201 -0
  30. package/src/dataflow/engine.js +52 -8
  31. package/src/dataflow/formal-verify.js +204 -0
  32. package/src/dataflow/ifds-precise.js +222 -0
  33. package/src/dataflow/k2-summary-cache.js +153 -0
  34. package/src/dataflow/lib-taint-summaries.js +198 -0
  35. package/src/dataflow/privacy-taint.js +205 -0
  36. package/src/dataflow/smt-feasibility.js +189 -0
  37. package/src/engine.js +890 -132
  38. package/src/integrations/index.js +2 -1
  39. package/src/ir/.agentic-security/findings.json +240 -6
  40. package/src/ir/.agentic-security/last-scan.json +240 -6
  41. package/src/ir/.agentic-security/last-scan.json.sig +1 -1
  42. package/src/ir/.agentic-security/scan-history.json +16 -594
  43. package/src/ir/.agentic-security/streak.json +8 -9
  44. package/src/ir/callgraph.js +27 -7
  45. package/src/ir/cpp-preprocessor.js +142 -0
  46. package/src/ir/csharp-ir.js +604 -0
  47. package/src/ir/universal-ir.js +403 -0
  48. package/src/llm-validator/index.js +7 -5
  49. package/src/mcp/.agentic-security/findings.json +8632 -0
  50. package/src/mcp/.agentic-security/last-scan.json +8632 -0
  51. package/src/mcp/.agentic-security/last-scan.json.sig +1 -0
  52. package/src/mcp/.agentic-security/scan-history.json +143 -0
  53. package/src/mcp/.agentic-security/streak.json +20 -0
  54. package/src/mcp/audit.js +5 -0
  55. package/src/mcp/tools.js +90 -1
  56. package/src/posture/.agentic-security/findings.json +16809 -4367
  57. package/src/posture/.agentic-security/last-scan.json +16809 -4367
  58. package/src/posture/.agentic-security/last-scan.json.sig +1 -1
  59. package/src/posture/.agentic-security/scan-history.json +6689 -177
  60. package/src/posture/.agentic-security/streak.json +8 -7
  61. package/src/posture/api-contract.js +193 -0
  62. package/src/posture/attack-taxonomy.js +227 -0
  63. package/src/posture/calibration-drift.js +2 -1
  64. package/src/posture/calibration.js +3 -2
  65. package/src/posture/compliance-policy.js +218 -0
  66. package/src/posture/composite-risk.js +122 -0
  67. package/src/posture/csharp-analysis.js +330 -0
  68. package/src/posture/exploit-bundle.js +210 -0
  69. package/src/posture/federated-learning.js +172 -0
  70. package/src/posture/fix-history.js +8 -2
  71. package/src/posture/license-attributions.js +94 -0
  72. package/src/posture/license-graph.js +238 -0
  73. package/src/posture/pqc-migration-plan.js +158 -0
  74. package/src/posture/profile.js +4 -5
  75. package/src/posture/reachability-filter.js +33 -2
  76. package/src/posture/realtime-cve-monitor.js +214 -0
  77. package/src/posture/rule-overrides.js +2 -3
  78. package/src/posture/rule-pack-signing.js +2 -3
  79. package/src/posture/rule-synthesis.js +5 -6
  80. package/src/posture/runtime-correlation.js +174 -0
  81. package/src/posture/sbom-diff.js +171 -0
  82. package/src/posture/sca-policy.js +235 -0
  83. package/src/posture/sca-upgrade.js +259 -0
  84. package/src/posture/security-trend.js +4 -7
  85. package/src/posture/state-dir.js +124 -0
  86. package/src/posture/streak.js +3 -0
  87. package/src/posture/suppressions.js +5 -8
  88. package/src/posture/threat-model-auto.js +268 -0
  89. package/src/posture/triage-learning.js +170 -0
  90. package/src/posture/triage.js +29 -6
  91. package/src/posture/validator-metrics.js +3 -6
  92. package/src/sast/.agentic-security/findings.json +996 -32
  93. package/src/sast/.agentic-security/last-scan.json +996 -32
  94. package/src/sast/.agentic-security/last-scan.json.sig +1 -1
  95. package/src/sast/.agentic-security/scan-history.json +565 -32
  96. package/src/sast/.agentic-security/streak.json +10 -8
  97. package/src/sast/_secret-entropy.js +145 -0
  98. package/src/sast/cloud-iam.js +312 -0
  99. package/src/sast/cpp.js +138 -4
  100. package/src/sast/crypto-protocol.js +388 -0
  101. package/src/sast/csharp-tokenizer.js +392 -0
  102. package/src/sast/csharp.js +924 -138
  103. package/src/sast/dapp-frontend.js +200 -0
  104. package/src/sast/db-taint.js +24 -0
  105. package/src/sast/k8s-admission.js +271 -0
  106. package/src/sast/llm-app.js +272 -0
  107. package/src/sast/ml-supply-chain.js +259 -0
  108. package/src/sast/mobile.js +224 -0
  109. package/src/sast/post-quantum-crypto.js +348 -0
  110. package/src/sast/rust.js +26 -0
  111. package/src/sast/web3-advanced.js +375 -0
  112. package/src/sca/.agentic-security/findings.json +6044 -171
  113. package/src/sca/.agentic-security/last-scan.json +6044 -171
  114. package/src/sca/.agentic-security/last-scan.json.sig +1 -1
  115. package/src/sca/.agentic-security/scan-history.json +83 -6
  116. package/src/sca/.agentic-security/streak.json +9 -9
  117. package/src/sca/CLAUDE.md +161 -0
  118. package/src/sca/binary-metadata.js +146 -0
  119. package/src/sca/py-package-functions.js +118 -0
  120. package/src/sca/sigstore-verify.js +215 -0
  121. package/src/sca/vendor-detect.js +53 -0
  122. package/src/report/.agentic-security/findings.json +0 -80
  123. package/src/report/.agentic-security/last-scan.json +0 -80
  124. package/src/report/.agentic-security/last-scan.json.sig +0 -1
  125. package/src/report/.agentic-security/scan-history.json +0 -35
  126. package/src/report/.agentic-security/streak.json +0 -22
@@ -0,0 +1,215 @@
1
+ // Sigstore + SLSA provenance verification — Recommendation #7 of the
2
+ // world-class roadmap.
3
+ //
4
+ // Current SCA pipeline reads OSV / KEV / EPSS for KNOWN-CVE data. World-class
5
+ // supply chain ALSO verifies cryptographic provenance: every dependency
6
+ // must have a Sigstore-signed attestation tying it to its declared source
7
+ // repo's CI pipeline. This detects supply-chain attacks at the *package-
8
+ // substitution* level (a malicious package published under a legitimate
9
+ // name) — the class OSV scanners are structurally blind to.
10
+ //
11
+ // Per-component, we query Rekor (Sigstore's transparency log) for
12
+ // attestations matching the package's SHA-256 digest. We then verify:
13
+ // 1. An attestation exists in Rekor
14
+ // 2. The attestation's subject digest matches our locally-computed digest
15
+ // 3. (When available) The attestation carries SLSA build-level provenance
16
+ // with a builder ID we trust
17
+ // 4. The source repo URL in the attestation matches the package's
18
+ // declared repository field
19
+ //
20
+ // Output: each SCA finding gains a `provenance` field with one of:
21
+ // { state: 'verified', builder, source, slsaLevel }
22
+ // { state: 'unverified' } ← no attestation found
23
+ // { state: 'tampered', reason } ← attestation exists but doesn't match
24
+ // { state: 'unknown', reason } ← network error / Rekor unreachable
25
+ //
26
+ // Network access: Rekor's REST API. We use the same disk-cache pattern
27
+ // as the OSV/KEV/EPSS layer (cached under ~/.claude/agentic-security/
28
+ // sigstore-cache/<sha256>.json with 24h TTL). Gated by
29
+ // AGENTIC_SECURITY_OFFLINE=1 (no fetch) and disabled outside of
30
+ // AGENTIC_SECURITY_SIGSTORE=1 (opt-in v1).
31
+
32
+ import * as fs from 'node:fs';
33
+ import * as path from 'node:path';
34
+ import * as os from 'node:os';
35
+ import * as crypto from 'node:crypto';
36
+
37
+ const CACHE_DIR = path.join(os.homedir(), '.claude', 'agentic-security', 'sigstore-cache');
38
+ const TTL_MS = 24 * 60 * 60 * 1000;
39
+
40
+ // Rekor public instance.
41
+ // External-identifier exception: rekor.sigstore.dev is the canonical
42
+ // Sigstore transparency log — the literal string is part of the public
43
+ // API URL we query. Not text we generate.
44
+ const REKOR_API = 'https://rekor.sigstore.dev/api/v1';
45
+
46
+ function _ensureCache() { try { fs.mkdirSync(CACHE_DIR, { recursive: true }); } catch {} }
47
+ function _cachePath(key) {
48
+ const h = crypto.createHash('sha256').update(key).digest('hex');
49
+ return path.join(CACHE_DIR, h + '.json');
50
+ }
51
+ function _readCache(key) {
52
+ const fp = _cachePath(key);
53
+ if (!fs.existsSync(fp)) return null;
54
+ try {
55
+ const stat = fs.statSync(fp);
56
+ if (Date.now() - stat.mtimeMs > TTL_MS) return null;
57
+ return JSON.parse(fs.readFileSync(fp, 'utf8'));
58
+ } catch { return null; }
59
+ }
60
+ function _writeCache(key, v) {
61
+ _ensureCache();
62
+ try { fs.writeFileSync(_cachePath(key), JSON.stringify(v)); } catch {}
63
+ }
64
+
65
+ /**
66
+ * Query Rekor for entries whose subject hash matches `sha256Hex`. Returns
67
+ * an array of (verified-by-Rekor-membership-proof) entries, or empty if
68
+ * no entries exist or the network fails.
69
+ */
70
+ export async function queryRekor(sha256Hex) {
71
+ if (!sha256Hex || !/^[a-f0-9]{64}$/i.test(sha256Hex)) return [];
72
+ if (process.env.AGENTIC_SECURITY_OFFLINE === '1') {
73
+ const c = _readCache('rekor:' + sha256Hex);
74
+ return c || [];
75
+ }
76
+ const cached = _readCache('rekor:' + sha256Hex);
77
+ if (cached !== null) return cached;
78
+
79
+ try {
80
+ const url = `${REKOR_API}/index/retrieve`;
81
+ const body = { hash: 'sha256:' + sha256Hex };
82
+ const res = await fetch(url, {
83
+ method: 'POST',
84
+ headers: { 'Content-Type': 'application/json', 'User-Agent': 'agentic-security/0.1' },
85
+ body: JSON.stringify(body),
86
+ });
87
+ if (!res.ok) { _writeCache('rekor:' + sha256Hex, []); return []; }
88
+ const ids = await res.json();
89
+ if (!Array.isArray(ids) || !ids.length) { _writeCache('rekor:' + sha256Hex, []); return []; }
90
+ const out = [];
91
+ // Fetch up to 5 entries per query — Rekor entries can be voluminous.
92
+ for (const id of ids.slice(0, 5)) {
93
+ try {
94
+ const r = await fetch(`${REKOR_API}/log/entries/${encodeURIComponent(id)}`);
95
+ if (!r.ok) continue;
96
+ const entry = await r.json();
97
+ out.push({ id, entry });
98
+ } catch { /* skip */ }
99
+ }
100
+ _writeCache('rekor:' + sha256Hex, out);
101
+ return out;
102
+ } catch {
103
+ _writeCache('rekor:' + sha256Hex, []);
104
+ return [];
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Verify provenance for a single SCA component. Computes the component's
110
+ * SHA-256 (from its tarball / wheel / nupkg path), queries Rekor, and
111
+ * returns a structured provenance state.
112
+ *
113
+ * Per-package digest acquisition is ecosystem-specific:
114
+ * - npm: .integrity in package-lock.json (sha512 → sha256 via re-fetch)
115
+ * - pypi: hash from poetry.lock / Pipfile.lock
116
+ * - cargo: checksum from Cargo.lock
117
+ * - go: h1: prefix from go.sum
118
+ * In v1 we extract the published hash from the lockfile WHEN available
119
+ * and skip components without a recorded hash.
120
+ */
121
+ export async function verifyComponent(component) {
122
+ if (!component) return { state: 'unknown', reason: 'no-component' };
123
+ const digest = _digestFor(component);
124
+ if (!digest) return { state: 'unknown', reason: 'no-locally-recorded-digest' };
125
+ const entries = await queryRekor(digest);
126
+ if (!entries || entries.length === 0) return { state: 'unverified', digest };
127
+ // Heuristic: take the first entry that matches the component's
128
+ // declared source-repo URL (when available). Otherwise return the
129
+ // first entry's metadata.
130
+ const first = entries[0];
131
+ return {
132
+ state: 'verified',
133
+ digest,
134
+ rekorEntry: first.id,
135
+ builder: _extractBuilderFromEntry(first.entry),
136
+ source: _extractSourceFromEntry(first.entry),
137
+ slsaLevel: _inferSlsaLevel(first.entry),
138
+ };
139
+ }
140
+
141
+ function _digestFor(component) {
142
+ // Prefer an explicitly-recorded SHA-256.
143
+ if (component.sha256) return component.sha256.toLowerCase().replace(/^sha256:/, '');
144
+ // npm integrity field: sha512-... — we don't downgrade; v1 skips.
145
+ if (component.integrity && /^sha256-/i.test(component.integrity)) {
146
+ try {
147
+ const b64 = component.integrity.slice('sha256-'.length);
148
+ return Buffer.from(b64, 'base64').toString('hex');
149
+ } catch { /* fall through */ }
150
+ }
151
+ return null;
152
+ }
153
+
154
+ function _extractBuilderFromEntry(entry) {
155
+ // Rekor entry payloads carry a base64-encoded body. The body schema varies
156
+ // (intoto, hashedrekord, dsse). We extract a best-effort builder identifier
157
+ // by JSON-walking the decoded body for a "builder.id" key.
158
+ try {
159
+ const body = JSON.parse(Buffer.from(entry.body, 'base64').toString('utf8'));
160
+ return _findKey(body, 'builder')?.id || _findKey(body, 'builder_id') || null;
161
+ } catch { return null; }
162
+ }
163
+
164
+ function _extractSourceFromEntry(entry) {
165
+ try {
166
+ const body = JSON.parse(Buffer.from(entry.body, 'base64').toString('utf8'));
167
+ return _findKey(body, 'source')?.uri || _findKey(body, 'invocation')?.configSource?.uri || null;
168
+ } catch { return null; }
169
+ }
170
+
171
+ function _inferSlsaLevel(entry) {
172
+ try {
173
+ const body = JSON.parse(Buffer.from(entry.body, 'base64').toString('utf8'));
174
+ const pred = _findKey(body, 'predicateType') || _findKey(body, 'predicate_type');
175
+ if (!pred) return null;
176
+ const m = String(pred).match(/slsa\.dev\/provenance\/v(\d+(?:\.\d+)?)/i);
177
+ return m ? `SLSA-${m[1]}` : null;
178
+ } catch { return null; }
179
+ }
180
+
181
+ function _findKey(obj, key) {
182
+ if (!obj || typeof obj !== 'object') return null;
183
+ if (Object.prototype.hasOwnProperty.call(obj, key)) return obj[key];
184
+ for (const v of Object.values(obj)) {
185
+ const r = _findKey(v, key);
186
+ if (r) return r;
187
+ }
188
+ return null;
189
+ }
190
+
191
+ /**
192
+ * Annotate every SCA finding (vulnerable_dep or otherwise) with its
193
+ * provenance state. Caller already loaded `components` from parseManifests.
194
+ */
195
+ export async function annotateProvenance(supplyChain, components) {
196
+ if (!Array.isArray(supplyChain) || !Array.isArray(components)) return { verified: 0, unverified: 0 };
197
+ if (process.env.AGENTIC_SECURITY_SIGSTORE !== '1') return { skipped: true };
198
+ const byNameVer = new Map();
199
+ for (const c of components) byNameVer.set(`${c.ecosystem}:${c.name}:${c.version}`, c);
200
+ let verified = 0, unverified = 0, tampered = 0, unknown = 0;
201
+ for (const sc of supplyChain) {
202
+ if (sc.type !== 'vulnerable_dep') continue;
203
+ const c = byNameVer.get(`${sc.ecosystem}:${sc.name}:${sc.version}`);
204
+ if (!c) { sc.provenance = { state: 'unknown', reason: 'component-not-in-manifest' }; unknown++; continue; }
205
+ const r = await verifyComponent(c);
206
+ sc.provenance = r;
207
+ if (r.state === 'verified') verified++;
208
+ else if (r.state === 'unverified') unverified++;
209
+ else if (r.state === 'tampered') tampered++;
210
+ else unknown++;
211
+ }
212
+ return { verified, unverified, tampered, unknown };
213
+ }
214
+
215
+ export const _internals = { _digestFor, _extractBuilderFromEntry, _extractSourceFromEntry, _findKey, CACHE_DIR };
@@ -87,5 +87,58 @@ export function detectVendoredLibraries(fileContents) {
87
87
  }
88
88
  }
89
89
  }
90
+ // Pass 2: Function-body structural matching for minified/forked copies
91
+ const FUNCTION_BODY_SIGS = [
92
+ { pkg: 'lodash', ecosystem: 'npm', fn: 'merge', paramMin: 1,
93
+ bodyContains: ['assignValue', 'baseFor', 'isObject', 'baseMerge'] },
94
+ { pkg: 'lodash', ecosystem: 'npm', fn: 'template', paramMin: 1,
95
+ bodyContains: ['sourceURL', 'interpolate', 'evaluate', 'escape'] },
96
+ { pkg: 'lodash', ecosystem: 'npm', fn: 'defaultsDeep', paramMin: 1,
97
+ bodyContains: ['baseMerge', 'isMergeableObject', 'customDefaultsMerge'] },
98
+ { pkg: 'jquery', ecosystem: 'npm', fn: 'ajax', paramMin: 1,
99
+ bodyContains: ['XMLHttpRequest', 'ajaxSettings', 'crossDomain', 'responseFields'] },
100
+ { pkg: 'handlebars', ecosystem: 'npm', fn: 'compile', paramMin: 1,
101
+ bodyContains: ['templateSpec', 'container', 'invokePartial', 'blockParams'] },
102
+ { pkg: 'marked', ecosystem: 'npm', fn: 'parse', paramMin: 1,
103
+ bodyContains: ['Lexer', 'Parser', 'blockTokens', 'walkTokens'] },
104
+ { pkg: 'ejs', ecosystem: 'npm', fn: 'render', paramMin: 1,
105
+ bodyContains: ['includeFile', 'resolveInclude', 'rethrow', 'escapeFn'] },
106
+ { pkg: 'moment', ecosystem: 'npm', fn: 'format', paramMin: 0,
107
+ bodyContains: ['formatMoment', 'expandFormat', 'makeFormatFunction', 'localFormattingTokens'] },
108
+ { pkg: 'underscore', ecosystem: 'npm', fn: 'template', paramMin: 1,
109
+ bodyContains: ['interpolate', 'evaluate', 'escape', 'templateSettings'] },
110
+ { pkg: 'minimist', ecosystem: 'npm', fn: 'parse', paramMin: 1,
111
+ bodyContains: ['boolean', 'alias', 'default', 'stopEarly', 'unknown'] },
112
+ ];
113
+
114
+ for (const [fp, content] of Object.entries(fileContents)) {
115
+ if (!content || typeof content !== 'string') continue;
116
+ if (SKIP_DIRS.test(fp)) continue;
117
+ if (!/\.(?:js|mjs|cjs)$/i.test(fp)) continue;
118
+ if (content.length < 200 || content.length > 500_000) continue;
119
+
120
+ for (const sig of FUNCTION_BODY_SIGS) {
121
+ const key = `${sig.pkg}:${fp}`;
122
+ if (seen.has(key)) continue;
123
+ const fnRe = new RegExp(`(?:function\\s+${sig.fn}|(?:const|let|var)\\s+${sig.fn}\\s*=|${sig.fn}\\s*[:=]\\s*function)\\s*\\(`, 'g');
124
+ const m = fnRe.exec(content);
125
+ if (!m) continue;
126
+ const bodyWindow = content.slice(m.index, m.index + 2000);
127
+ const matchCount = sig.bodyContains.filter(kw => bodyWindow.includes(kw)).length;
128
+ if (matchCount < Math.ceil(sig.bodyContains.length * 0.6)) continue;
129
+ seen.add(key);
130
+ detected.push({
131
+ name: sig.pkg,
132
+ version: 'unknown',
133
+ ecosystem: sig.ecosystem,
134
+ file: fp,
135
+ scope: 'vendored',
136
+ isVendored: true,
137
+ _detectionMethod: 'function-body-signature',
138
+ _matchedKeywords: matchCount,
139
+ });
140
+ }
141
+ }
142
+
90
143
  return detected;
91
144
  }
@@ -1,80 +0,0 @@
1
- {
2
- "scanId": "db8e3115-87e6-4e90-8041-31f9921c7b54",
3
- "startedAt": "2026-05-27T11:09:28.873Z",
4
- "durationMs": 183,
5
- "scanned": {
6
- "files": 2,
7
- "lines": 0
8
- },
9
- "findings": [],
10
- "bundles": [],
11
- "routes": [],
12
- "components": [],
13
- "suppressedCount": 0,
14
- "blastRadiusSignals": {
15
- "industry": "generic",
16
- "industryConfidence": "low",
17
- "jurisdictions": [],
18
- "controls": [],
19
- "estimatedUsers": 50,
20
- "revenueIndicator": "pre-revenue",
21
- "hasStripe": false,
22
- "hasAuth": false,
23
- "hasUserTable": false,
24
- "hasPII": false,
25
- "hasPHI": false,
26
- "hasS3": false
27
- },
28
- "_v3": {
29
- "counterfactual": {
30
- "spofControls": [],
31
- "controlsDetected": 174
32
- },
33
- "threatModel": {
34
- "summary": {
35
- "assetCount": 0,
36
- "boundaryCount": 0,
37
- "strideCounts": {
38
- "spoofing": 0,
39
- "tampering": 0,
40
- "repudiation": 0,
41
- "informationDisclosure": 0,
42
- "denialOfService": 0,
43
- "elevationOfPrivilege": 0
44
- }
45
- },
46
- "assets": [],
47
- "trustBoundaries": [],
48
- "stride": {
49
- "spoofing": [],
50
- "tampering": [],
51
- "repudiation": [],
52
- "informationDisclosure": [],
53
- "denialOfService": [],
54
- "elevationOfPrivilege": []
55
- }
56
- },
57
- "trustBoundaryDiagram": {
58
- "mermaid": "flowchart LR\n INTERNET((Internet))\n APP[\"Application\"]\n classDef sev_critical fill:#ffcccc,stroke:#a00,stroke-width:2px;\n classDef sev_high fill:#ffe0b2,stroke:#c60,stroke-width:2px;\n classDef sev_medium fill:#fff3cd,stroke:#a80;\n classDef sev_low fill:#e8eaf6,stroke:#557;",
59
- "nodes": [
60
- {
61
- "id": "INTERNET",
62
- "kind": "external",
63
- "label": "Internet"
64
- },
65
- {
66
- "id": "APP",
67
- "kind": "app",
68
- "label": "Application"
69
- }
70
- ],
71
- "edges": [],
72
- "decorations": []
73
- },
74
- "calibrationDrift": {
75
- "alarms": [],
76
- "note": "no-feedback-data"
77
- }
78
- },
79
- "annotatorErrors": []
80
- }
@@ -1,80 +0,0 @@
1
- {
2
- "scanId": "db8e3115-87e6-4e90-8041-31f9921c7b54",
3
- "startedAt": "2026-05-27T11:09:28.873Z",
4
- "durationMs": 183,
5
- "scanned": {
6
- "files": 2,
7
- "lines": 0
8
- },
9
- "findings": [],
10
- "bundles": [],
11
- "routes": [],
12
- "components": [],
13
- "suppressedCount": 0,
14
- "blastRadiusSignals": {
15
- "industry": "generic",
16
- "industryConfidence": "low",
17
- "jurisdictions": [],
18
- "controls": [],
19
- "estimatedUsers": 50,
20
- "revenueIndicator": "pre-revenue",
21
- "hasStripe": false,
22
- "hasAuth": false,
23
- "hasUserTable": false,
24
- "hasPII": false,
25
- "hasPHI": false,
26
- "hasS3": false
27
- },
28
- "_v3": {
29
- "counterfactual": {
30
- "spofControls": [],
31
- "controlsDetected": 174
32
- },
33
- "threatModel": {
34
- "summary": {
35
- "assetCount": 0,
36
- "boundaryCount": 0,
37
- "strideCounts": {
38
- "spoofing": 0,
39
- "tampering": 0,
40
- "repudiation": 0,
41
- "informationDisclosure": 0,
42
- "denialOfService": 0,
43
- "elevationOfPrivilege": 0
44
- }
45
- },
46
- "assets": [],
47
- "trustBoundaries": [],
48
- "stride": {
49
- "spoofing": [],
50
- "tampering": [],
51
- "repudiation": [],
52
- "informationDisclosure": [],
53
- "denialOfService": [],
54
- "elevationOfPrivilege": []
55
- }
56
- },
57
- "trustBoundaryDiagram": {
58
- "mermaid": "flowchart LR\n INTERNET((Internet))\n APP[\"Application\"]\n classDef sev_critical fill:#ffcccc,stroke:#a00,stroke-width:2px;\n classDef sev_high fill:#ffe0b2,stroke:#c60,stroke-width:2px;\n classDef sev_medium fill:#fff3cd,stroke:#a80;\n classDef sev_low fill:#e8eaf6,stroke:#557;",
59
- "nodes": [
60
- {
61
- "id": "INTERNET",
62
- "kind": "external",
63
- "label": "Internet"
64
- },
65
- {
66
- "id": "APP",
67
- "kind": "app",
68
- "label": "Application"
69
- }
70
- ],
71
- "edges": [],
72
- "decorations": []
73
- },
74
- "calibrationDrift": {
75
- "alarms": [],
76
- "note": "no-feedback-data"
77
- }
78
- },
79
- "annotatorErrors": []
80
- }
@@ -1 +0,0 @@
1
- e3726a5fd5c2a4b763554484c083d9136dbb026f1f913a0c9b35e3455711b303
@@ -1,35 +0,0 @@
1
- [
2
- {
3
- "timestamp": "2026-05-27T11:06:13.261Z",
4
- "label": "scan",
5
- "total": 0,
6
- "critical": 0,
7
- "high": 0,
8
- "medium": 0,
9
- "low": 0,
10
- "kev": 0,
11
- "ids": []
12
- },
13
- {
14
- "timestamp": "2026-05-27T11:07:38.301Z",
15
- "label": "scan",
16
- "total": 0,
17
- "critical": 0,
18
- "high": 0,
19
- "medium": 0,
20
- "low": 0,
21
- "kev": 0,
22
- "ids": []
23
- },
24
- {
25
- "timestamp": "2026-05-27T11:09:29.055Z",
26
- "label": "scan",
27
- "total": 0,
28
- "critical": 0,
29
- "high": 0,
30
- "medium": 0,
31
- "low": 0,
32
- "kev": 0,
33
- "ids": []
34
- }
35
- ]
@@ -1,22 +0,0 @@
1
- {
2
- "firstScanDate": "2026-05-27T11:06:13.266Z",
3
- "lastScanDate": "2026-05-27T11:09:29.061Z",
4
- "totalScans": 3,
5
- "daysCleanCritical": 1,
6
- "lastCleanDate": "2026-05-27",
7
- "lastCriticalDate": null,
8
- "hasEverHadCritical": false,
9
- "bestDaysCleanCritical": 1,
10
- "totalFindingsAtFirstScan": 0,
11
- "totalFindingsAtLastScan": 0,
12
- "totalFixesInferred": 0,
13
- "lastGrade": "A+",
14
- "bestGrade": "A+",
15
- "launchCheckPassedAt": null,
16
- "achievements": [
17
- "first-scan",
18
- "grade-a",
19
- "grade-a-plus"
20
- ],
21
- "previousGrade": "A+"
22
- }