Server definition
- Hash
- sha256:5884ca174de2dc4421a4d8db70a9b479e36edce1e7c6a7d898bd9735ac04700e
- What it is
- What a remote MCP server returned when asked what it offers: 14 tools
The blob, as servednamed by its sha256
{
"instructions": "EchelonGraph's public CVE and internet-exposure data, read-only and keyless. Everything these tools return is public: EchelonGraph's CVE Pulse feed, and aggregate, host-redacted totals from its exposure radars. Every result says how it was measured: state, measured_at, method, coverage, freshness and notes, in its structuredContent and again in its text. Its last text block is that structuredContent as JSON, less what an earlier text block already gives verbatim: data, which is a success's first text block; the sentences of the text block just before it (the note, or a failure's message), with which structuredContent's notes end; and method, where that block quotes it. state is measured, not_assessed, failed or invalid_input. not_assessed means the answer holds no dated measurement of what was asked, so no count in it is presented as one. It can still relay a count, as what the source holds on record, undated, and its notes say what each count is: cve_exposure's exposed_hosts when its exposure_state is exposed, and exposure_radar's labelled totals, are such counts. A zero is not a finding of no exposure where the answer holds no measurement for that CVE, for example a CVE outside the KEV-exposure radar's tracked set (exposure_state not_assessed). failed and invalid_input mean nothing was measured: never report them as zero, none found or unexposed. measured_at is when the underlying observation was made, and null when the answer does not say or holds none. freshness gives the producing radar's last_run_at: when it last completed a check whose reads succeeded. That is not the time of every record the radar's numbers count, which cover everything still on record, and it is null when the API does not say. Every figure is as fresh as the schedule that refreshes it. Exposure numbers are aggregate: counts of distinct ip:port services on EchelonGraph's record (a machine answering on two ports counts twice), not machines, and not an internet-wide census. exposure_radar's mcp_servers counts hostnames instead, each by its latest verdict on record. Exposure counts are derived from Shodan data. Shodan data is owned by Shodan, which holds its copyright (© Shodan). exposure_radar's mcp_servers counts use no Shodan data: their hostnames come from EchelonGraph's own Certificate Transparency feed.",
"tools": [
{
"description": "Whether a product or package at a given version is affected by known CVEs, from the same matcher as echelongraph.io/am-i-affected. Two lookup paths. The CPE path takes product (the NVD CPE product token, such as openssl or nginx) and version, and returns the CVEs whose NVD CPE match criteria name that product with a version range that includes the version; it matches the token across vendors, so each match names the vendor NVD asserts (cpe_vendor) and whether that vendor was verified (vendor_unknown). The registry path takes ecosystem (npm, PyPI, Maven and other OSV ecosystem names), package and version, and decides each OSV advisory record EchelonGraph holds for that package as affected, not affected or undetermined. Read assessed before count: assessed false means the lookup did not evaluate this component, not_assessed_reason says why (product_not_in_cpe_corpus, package_not_cpe_nameable, candidate_load_pending, candidate_window_truncated, package_not_in_advisory_corpus, no_decidable_advisory), the structured result's state is not_assessed, and a count of 0 there must never be reported as not affected. An advisory whose version range cannot be decided at this version is reported as undetermined (undetermined_count, and up to 50 of them in undetermined), never as safe. The answer also carries match_layer (which path answered), capped (the match list stopped at its cap), candidates_capped (not every candidate CVE was loaded), excluded_count (CPE candidates suppressed by the vendor or platform gate), not_affected_count (advisories decided in your favour) and degraded (the lookup ran out of time). Each match carries cve_id, kev_listed, ransomware, epss_score, effective_score, effective_severity and score_assessed (false: EchelonGraph has not scored the CVE yet, so its echelongraph_score is withheld). Product, version, ecosystem and package travel in request headers, never in the URL. Its structured result carries state (measured only when the answer says assessed true), measured_at (null), method (which matcher answered), coverage (assessed and not_assessed_reason first, then the lookup path and the counts above), freshness (null) and notes, with data equal to the API's JSON.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"ecosystem": {
"description": "Registry path: the package's ecosystem, such as npm, PyPI or Maven. Give with package, not with product.",
"type": "string"
},
"package": {
"description": "Registry path: the package name in that ecosystem, such as lodash.",
"type": "string"
},
"product": {
"description": "CPE path: the NVD CPE product token, such as openssl, nginx or linux_kernel. Leave out for the registry path.",
"type": "string"
},
"version": {
"description": "The version to check, such as 3.0.0.",
"type": "string"
}
},
"required": [
"version"
],
"type": "object"
},
"name": "check_affected",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"assessed": {
"description": "The answer's assessed, first: null when the answer does not say.",
"type": [
"boolean",
"null"
]
},
"candidates_capped": {
"type": [
"boolean",
"null"
]
},
"capped": {
"type": [
"boolean",
"null"
]
},
"count": {
"type": [
"number",
"null"
]
},
"degraded": {
"type": [
"boolean",
"null"
]
},
"excluded_count": {
"type": [
"number",
"null"
]
},
"lookup": {
"description": "Which lookup path this call asked for.",
"enum": [
"cpe",
"registry"
],
"type": "string"
},
"match_layer": {
"type": [
"string",
"null"
]
},
"not_affected_count": {
"type": [
"number",
"null"
]
},
"not_assessed_reason": {
"anyOf": [
{
"anyOf": [
{
"enum": [
"product_not_in_cpe_corpus",
"package_not_cpe_nameable",
"candidate_load_pending",
"candidate_window_truncated",
"package_not_in_advisory_corpus",
"no_decidable_advisory",
"advisory_lookup_failed"
],
"type": "string"
},
{
"type": "string"
}
],
"description": "Why assessed is false; empty or absent when it is true."
},
{
"type": "null"
}
]
},
"undetermined_count": {
"type": [
"number",
"null"
]
}
},
"required": [
"assessed",
"not_assessed_reason",
"lookup",
"match_layer",
"count",
"capped",
"candidates_capped",
"excluded_count",
"undetermined_count",
"not_affected_count",
"degraded"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": {},
"properties": {
"advisories_considered": {
"type": [
"number",
"null"
]
},
"assessed": {
"description": "Read first. true: the lookup evaluated this component. false: it did not, and count 0 says nothing about whether this version is affected.",
"type": [
"boolean",
"null"
]
},
"candidate_count": {
"type": [
"number",
"null"
]
},
"candidates_capped": {
"type": [
"boolean",
"null"
]
},
"capped": {
"type": [
"boolean",
"null"
]
},
"count": {
"type": [
"number",
"null"
]
},
"cve_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
]
},
"degraded": {
"type": [
"boolean",
"null"
]
},
"ecosystem": {
"type": [
"string",
"null"
]
},
"ecosystem_recognised": {
"type": [
"boolean",
"null"
]
},
"excluded": {},
"excluded_count": {
"type": [
"number",
"null"
]
},
"match_layer": {
"type": [
"string",
"null"
]
},
"matches": {
"anyOf": [
{
"items": {
"additionalProperties": {},
"properties": {
"cpe_vendor": {
"description": "The vendor NVD's CPE asserts for this match.",
"type": [
"string",
"null"
]
},
"cve_id": {
"type": [
"string",
"null"
]
},
"cvss_v2_score": {
"type": [
"number",
"null"
]
},
"cvss_v3_score": {
"type": [
"number",
"null"
]
},
"cvss_v4_score": {
"type": [
"number",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"echelongraph_score": {
"description": "EchelonGraph's 0-10 score: present only when score_assessed is true.",
"type": [
"number",
"null"
]
},
"echelongraph_severity": {
"type": [
"string",
"null"
]
},
"effective_score": {
"description": "The best real score held for the CVE (EchelonGraph's, else CVSS), the number the matches are ranked by.",
"type": [
"number",
"null"
]
},
"effective_severity": {
"description": "The band of effective_score; absent or empty when the CVE has no band at all (unrated, not harmless).",
"type": [
"string",
"null"
]
},
"epss_score": {
"description": "EPSS exploitation probability, 0 to 1.",
"type": [
"number",
"null"
]
},
"kev_listed": {
"description": "Listed in CISA-KEV: known to be exploited.",
"type": [
"boolean",
"null"
]
},
"match_confidence": {
"type": [
"number",
"null"
]
},
"match_method": {
"type": [
"string",
"null"
]
},
"match_reason": {
"type": [
"string",
"null"
]
},
"matched_criteria": {
"type": [
"string",
"null"
]
},
"ransomware": {
"description": "CISA-KEV records known use in ransomware campaigns.",
"type": [
"boolean",
"null"
]
},
"score_assessed": {
"description": "Whether EchelonGraph has scored the CVE. false: NOT YET SCORED, and echelongraph_score is withheld.",
"type": [
"boolean",
"null"
]
},
"score_unassessed_reason": {
"type": [
"string",
"null"
]
},
"severity": {
"description": "NVD's own CVSS v3 band, as provenance: it can be NONE for a CVE NVD rated only under CVSS v2. Rank and display on effective_severity.",
"type": [
"string",
"null"
]
},
"vendor_severity": {
"type": [
"string",
"null"
]
},
"vendor_unknown": {
"description": "true: the vendor was not verified, so the match is real but its attribution to your vendor is not.",
"type": [
"boolean",
"null"
]
},
"version_evidence": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
]
},
"not_affected_count": {
"type": [
"number",
"null"
]
},
"not_assessed_reason": {
"anyOf": [
{
"anyOf": [
{
"enum": [
"product_not_in_cpe_corpus",
"package_not_cpe_nameable",
"candidate_load_pending",
"candidate_window_truncated",
"package_not_in_advisory_corpus",
"no_decidable_advisory",
"advisory_lookup_failed"
],
"type": "string"
},
{
"type": "string"
}
],
"description": "Why assessed is false; empty or absent when it is true."
},
{
"type": "null"
}
]
},
"package": {
"type": [
"string",
"null"
]
},
"product": {
"type": [
"string",
"null"
]
},
"product_named_count": {
"type": [
"number",
"null"
]
},
"undecidable_excluded_count": {
"type": [
"number",
"null"
]
},
"undecided_candidate_count": {
"type": [
"number",
"null"
]
},
"undetermined": {
"anyOf": [
{
"items": {
"additionalProperties": {},
"properties": {
"cve_id": {
"type": [
"string",
"null"
]
},
"detail": {
"type": [
"string",
"null"
]
},
"ecosystem": {
"type": [
"string",
"null"
]
},
"package": {
"type": [
"string",
"null"
]
},
"reason": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
]
},
"undetermined_count": {
"type": [
"number",
"null"
]
},
"vendor": {
"type": [
"string",
"null"
]
},
"vendor_advisory_count": {
"type": [
"number",
"null"
]
},
"version": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"assessed": {
"description": "The answer's assessed, first: null when the answer does not say.",
"type": [
"boolean",
"null"
]
},
"candidates_capped": {
"type": [
"boolean",
"null"
]
},
"capped": {
"type": [
"boolean",
"null"
]
},
"count": {
"type": [
"number",
"null"
]
},
"degraded": {
"type": [
"boolean",
"null"
]
},
"excluded_count": {
"type": [
"number",
"null"
]
},
"lookup": {
"description": "Which lookup path this call asked for.",
"enum": [
"cpe",
"registry"
],
"type": "string"
},
"match_layer": {
"type": [
"string",
"null"
]
},
"not_affected_count": {
"type": [
"number",
"null"
]
},
"not_assessed_reason": {
"anyOf": [
{
"anyOf": [
{
"enum": [
"product_not_in_cpe_corpus",
"package_not_cpe_nameable",
"candidate_load_pending",
"candidate_window_truncated",
"package_not_in_advisory_corpus",
"no_decidable_advisory",
"advisory_lookup_failed"
],
"type": "string"
},
{
"type": "string"
}
],
"description": "Why assessed is false; empty or absent when it is true."
},
{
"type": "null"
}
]
},
"undetermined_count": {
"type": [
"number",
"null"
]
}
},
"required": [
"assessed",
"not_assessed_reason",
"lookup",
"match_layer",
"count",
"capped",
"candidates_capped",
"excluded_count",
"undetermined_count",
"not_affected_count",
"degraded"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "Check a dependency list against EchelonGraph's advisory corpus, one verdict per component. Pass purls (package URLs, up to 2,000 distinct) or sbom (a CycloneDX JSON or SPDX JSON document, as JSON text or as an object, up to 5,000,000 characters). The purls are read from the document on this machine and only they are sent, in POST bodies of at most 200 purls each, one after another, never in a URL; the document itself is not sent. A component without a purl is counted and not checked. Each purl is mapped to its OSV ecosystem, package name and version and matched against the affected version ranges EchelonGraph holds from OSV.dev advisory records; there is no ranking and no score. data.results holds one row per component sent, in order (index counts across batches), with verdict (affected, not_affected, undetermined or not_assessed), assessed, not_assessed_reason, cve_ids, matches, count, not_affected_count and undetermined_count; data.summary counts the verdicts, summed over the batches (partial is true when any batch's was). not_affected is the only clean verdict. undetermined: advisories name the package but at least one could not be decided at this version and none matched. not_assessed: no verdict at all, because the package is not in the corpus, the purl type has no OSV ecosystem, a deb, apk or rpm purl carries no distro qualifier naming its release (EchelonGraph does not guess one), the version is missing, the lookup failed, or the batch's time budget ran out first (time_budget). Neither undetermined nor not_assessed is clean, and the note gives their counts. The API allows 1,200 components a minute per caller; when it answers 429 with Retry-After, the tool waits as asked and sends the batch again, within 50 seconds per call. When the next wait would pass that, or a batch after the first fails, the tool stops and answers what it has: coverage.not_sent counts the purls not sent and coverage.not_sent_reason says why (time_budget, rate_limited or request_failed), data.not_sent_purls lists them for a later call, and they are not checked and not clean. A list or document with more than 2,000 distinct purls is refused, not truncated: split it. Its structured result carries state (measured when at least one component got a verdict, else not_assessed), measured_at (null: the corpus is read through a cache, so no single read time exists), method, coverage (what the input held, what was sent in how many batches, and what was not sent and why), freshness (null) and notes, with data equal to the API's JSON (for more than one batch, the batches' answers merged); the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"purls": {
"description": "package URLs to check, e.g. pkg:npm/[email protected] or pkg:deb/debian/[email protected]~deb12u1?distro=debian-12 (up to 2,000 distinct, sent in batches of 200)",
"items": {
"type": "string"
},
"type": "array"
},
"sbom": {
"anyOf": [
{
"type": "string"
},
{
"additionalProperties": {},
"propertyNames": {
"type": "string"
},
"type": "object"
}
],
"description": "a CycloneDX JSON or SPDX JSON document, as JSON text or as an object; its purls are read here and only they are sent"
}
},
"type": "object"
},
"name": "check_sbom",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"batch_size": {
"description": "The most purls one request carries (the API's cap per request).",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"batches": {
"description": "Requests the distinct purls make, at batch_size each.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"batches_sent": {
"description": "Of those, the ones the API answered.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"components_in_document": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
},
"distinct_purls": {
"description": "Distinct purls to check: sent plus not_sent.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"duplicates_removed": {
"description": "Purls that appeared more than once and were sent once.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"input": {
"description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
"enum": [
"purls",
"cyclonedx",
"spdx"
],
"type": "string"
},
"not_assessed": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Of those sent, the components with no verdict, as the answer counts them."
},
"not_sent": {
"description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"not_sent_reason": {
"anyOf": [
{
"enum": [
"time_budget",
"rate_limited",
"request_failed"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
},
"partial": {
"description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
"type": [
"boolean",
"null"
]
},
"rate_limit_waits": {
"description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"sent": {
"description": "Distinct purls sent and answered.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"waited_ms": {
"description": "Milliseconds spent in those waits.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"with_purl": {
"description": "Of those, the ones carrying a purl.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"without_purl": {
"description": "The ones without a purl: not checked, and not clean.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
}
},
"required": [
"input",
"components_in_document",
"with_purl",
"without_purl",
"duplicates_removed",
"distinct_purls",
"batch_size",
"batches",
"batches_sent",
"sent",
"not_sent",
"not_sent_reason",
"rate_limit_waits",
"waited_ms",
"not_assessed",
"partial"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": {},
"properties": {
"answered_at": {
"type": [
"string",
"null"
]
},
"components": {
"type": [
"number",
"null"
]
},
"match_layer": {
"type": [
"string",
"null"
]
},
"not_sent_purls": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The distinct purls not sent (coverage.not_sent_reason says why): not checked, and not clean. Present only when some were not sent."
},
"results": {
"items": {
"additionalProperties": {},
"properties": {
"advisories_considered": {
"type": [
"number",
"null"
]
},
"assessed": {
"description": "Whether the matcher produced a verdict for this component. false is never clean.",
"type": [
"boolean",
"null"
]
},
"candidates_capped": {
"type": [
"boolean",
"null"
]
},
"capped": {
"type": [
"boolean",
"null"
]
},
"code": {
"type": [
"string",
"null"
]
},
"count": {
"type": [
"number",
"null"
]
},
"cve_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
]
},
"ecosystem": {
"type": [
"string",
"null"
]
},
"error": {
"type": [
"string",
"null"
]
},
"index": {
"type": [
"number",
"null"
]
},
"input_kind": {
"type": [
"string",
"null"
]
},
"matches": {
"anyOf": [
{
"items": {
"additionalProperties": {},
"properties": {
"cve_id": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
]
},
"not_affected_count": {
"type": [
"number",
"null"
]
},
"not_assessed_reason": {
"description": "Why assessed is false: package_not_in_advisory_corpus, no_decidable_advisory, advisory_lookup_failed, candidate_window_truncated, time_budget, distro_release_unknown, purl_type_unsupported, version_missing or invalid_component.",
"type": [
"string",
"null"
]
},
"package": {
"type": [
"string",
"null"
]
},
"purl": {
"type": [
"string",
"null"
]
},
"undetermined": {
"anyOf": [
{
"items": {
"additionalProperties": {},
"properties": {
"cve_id": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
]
},
"undetermined_count": {
"type": [
"number",
"null"
]
},
"verdict": {
"description": "affected (count > 0); not_affected (assessed, no match, nothing undetermined: the only clean verdict); undetermined (advisories name the package, at least one could not be decided, none matched: not clean); not_assessed (no verdict: not clean).",
"type": [
"string",
"null"
]
},
"version": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"summary": {
"additionalProperties": {},
"properties": {
"affected": {
"type": [
"number",
"null"
]
},
"components": {
"type": [
"number",
"null"
]
},
"corpus_cache_max_age_ms": {
"type": [
"number",
"null"
]
},
"elapsed_ms": {
"type": [
"number",
"null"
]
},
"lookups": {
"type": [
"number",
"null"
]
},
"not_affected": {
"description": "Components with a decided, clean verdict.",
"type": [
"number",
"null"
]
},
"not_assessed": {
"description": "Components with no verdict: not clean.",
"type": [
"number",
"null"
]
},
"not_assessed_by_reason": {
"anyOf": [
{
"additionalProperties": {},
"properties": {
"advisory_lookup_failed": {
"type": "number"
},
"candidate_window_truncated": {
"type": "number"
},
"distro_release_unknown": {
"description": "deb, apk or rpm purls without a distro qualifier naming the release, which EchelonGraph does not guess.",
"type": "number"
},
"invalid_component": {
"type": "number"
},
"no_decidable_advisory": {
"type": "number"
},
"package_not_in_advisory_corpus": {
"type": "number"
},
"purl_type_unsupported": {
"type": "number"
},
"time_budget": {
"description": "Components the batch's time budget ran out before: not clean; check them again.",
"type": "number"
},
"version_missing": {
"type": "number"
}
},
"type": "object"
},
{
"type": "null"
}
],
"description": "The not_assessed components, counted by not_assessed_reason."
},
"partial": {
"description": "true when the time budget ran out before every component was looked up.",
"type": [
"boolean",
"null"
]
},
"time_budget_ms": {
"type": [
"number",
"null"
]
},
"undetermined": {
"description": "Components whose advisories could not all be decided and none matched: not clean.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"batch_size": {
"description": "The most purls one request carries (the API's cap per request).",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"batches": {
"description": "Requests the distinct purls make, at batch_size each.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"batches_sent": {
"description": "Of those, the ones the API answered.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"components_in_document": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Components (CycloneDX) or packages (SPDX) in the document; null for a purl list."
},
"distinct_purls": {
"description": "Distinct purls to check: sent plus not_sent.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"duplicates_removed": {
"description": "Purls that appeared more than once and were sent once.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"input": {
"description": "What was passed: a purl list, a CycloneDX JSON document or an SPDX JSON document.",
"enum": [
"purls",
"cyclonedx",
"spdx"
],
"type": "string"
},
"not_assessed": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Of those sent, the components with no verdict, as the answer counts them."
},
"not_sent": {
"description": "Distinct purls not sent, listed in data.not_sent_purls: not checked, and not clean.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"not_sent_reason": {
"anyOf": [
{
"enum": [
"time_budget",
"rate_limited",
"request_failed"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Why not_sent is above 0: time_budget (the call's 50 s budget ran out, or waiting out the API's Retry-After would pass it), rate_limited (a 429 without Retry-After, or a 429 after 10 waits), request_failed (a batch after the first failed; the note quotes how). null when every purl was sent."
},
"partial": {
"description": "true when not every purl was sent (not_sent above 0) or any batch's summary.partial was true (its time budget ran out first); otherwise the answer's summary.partial.",
"type": [
"boolean",
"null"
]
},
"rate_limit_waits": {
"description": "How many times the API answered 429 and the tool waited its Retry-After before sending the batch again.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"sent": {
"description": "Distinct purls sent and answered.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"waited_ms": {
"description": "Milliseconds spent in those waits.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"with_purl": {
"description": "Of those, the ones carrying a purl.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"without_purl": {
"description": "The ones without a purl: not checked, and not clean.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
}
},
"required": [
"input",
"components_in_document",
"with_purl",
"without_purl",
"duplicates_removed",
"distinct_purls",
"batch_size",
"batches",
"batches_sent",
"sent",
"not_sent",
"not_sent_reason",
"rate_limit_waits",
"waited_ms",
"not_assessed",
"partial"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "Internet-exposure footprint for one CVE from EchelonGraph's KEV-exposure radar: how many internet-facing services (distinct ip:port, returned as exposed_hosts; a machine answering on two ports counts twice) the radar has on record running a version its CVE matcher maps to this CVE, with a country/product breakdown and a ransomware flag. Aggregate and host-redacted; free and keyless. Method: exposure counts are derived from Shodan data. Shodan data is owned by Shodan, which holds its copyright (© Shodan). Every 12 h, when Shodan query credits allow, the radar runs one Shodan query per tracked product, reads up to 100 ip:port services per query, and keeps a service when its banner version matches a CISA-KEV or high-EPSS CVE; a service whose row has not been written or refreshed for 21 days is dropped. last_seen is when EchelonGraph last wrote or refreshed a service's row, not when the service was observed and not when its vulnerable version was last confirmed: it is set to the time of the write when a search matches the banner, and again when a re-check finds the port still listed by Shodan InternetDB, without re-reading the banner, so a patched service can stay counted while its port stays open. A count is therefore a banner-version inference over a sample, not an exploit test and not an internet-wide census. The radar only looks for its tracked set of CVEs: for a CVE outside that set the note says NOT ASSESSED (exposure_state not_assessed), and its 0 is not a measurement. Its structured result's state is not_assessed with measured_at null: the per-CVE answer says when EchelonGraph last wrote a row (last_seen), not when any counted service was observed, so no count is presented as a dated measurement; the count is still relayed, labelled, as what the radar holds on record. exposure_state says what the count is: exposed, measured_zero, not_assessed or tracking_unknown; coverage.in_scope is the API's tracked verdict; freshness is null, since the per-CVE answer carries no last completed check; data is the API's JSON. The result's last text block repeats the structured result without data (the first text block), without the note's sentences (the text block before it), with which notes ends, and without method where the note quotes it verbatim (\"Method: …\").",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cve_id": {
"description": "a CVE ID, e.g. CVE-2023-44487",
"type": "string"
}
},
"required": [
"cve_id"
],
"type": "object"
},
"name": "cve_exposure",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"in_scope": {
"description": "The API's tracked verdict: whether the CVE is in the radar's tracked set; null when the answer does not say.",
"type": [
"boolean",
"null"
]
}
},
"required": [
"in_scope"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": {},
"properties": {
"countries": {
"type": [
"number",
"null"
]
},
"cve_id": {
"type": [
"string",
"null"
]
},
"exposed_hosts": {
"type": [
"number",
"null"
]
},
"generated_at": {
"type": [
"string",
"null"
]
},
"kev_catalog_listed": {
"type": [
"boolean",
"null"
]
},
"kev_listed": {
"type": [
"boolean",
"null"
]
},
"kev_seen_in_observations": {
"type": [
"boolean",
"null"
]
},
"last_seen": {
"type": [
"string",
"null"
]
},
"method": {
"type": [
"string",
"null"
]
},
"ransomware": {
"type": [
"boolean",
"null"
]
},
"top_countries": {
"anyOf": [
{
"items": {
"additionalProperties": {},
"properties": {
"country": {
"type": [
"string",
"null"
]
},
"hosts": {
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
]
},
"top_products": {
"anyOf": [
{
"items": {
"additionalProperties": {},
"properties": {
"hosts": {
"type": [
"number",
"null"
]
},
"product": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
]
},
"tracked": {
"type": [
"boolean",
"null"
]
}
},
"type": "object"
},
"exposure_state": {
"anyOf": [
{
"enum": [
"exposed",
"measured_zero",
"not_assessed",
"tracking_unknown"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "What the answer's count is, as the note's (exposure_state: …) tag says; not state, which says whether the answer is a dated measurement. exposed: data.exposed_hosts counts the services the radar holds on record for the CVE, above 0. measured_zero: the API marks the CVE as tracked with 0 services, a zero in the radar's sample. not_assessed: the CVE is outside the radar's tracked set, so its count, if any, is not a current measurement. tracking_unknown: the API does not say whether the radar tracks the CVE, so its 0 is not evidence either way. null: the answer carries no count."
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"exposure_state",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"in_scope": {
"description": "The API's tracked verdict: whether the CVE is in the radar's tracked set; null when the answer does not say.",
"type": [
"boolean",
"null"
]
}
},
"required": [
"in_scope"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "Weakness, public exploit code, affected packages and fixed versions for one CVE, from EchelonGraph's per-CVE enrichment. Returns cwes (each cwe_id with its name and source), exploits (each with kind, source_name, source_url, first_seen_at and verified_status; at most 10, verified first) with exploits_total (every reference on record), exploits_capped (true when exploits lists fewer than exploits_total), exploits_by_kind and exploits_by_status, affected_packages (ecosystem, package_name, version_range, fixed_version), fixed_versions (ecosystem, package_name, vulnerable_range, fixed_version) and timeline (the newest enrichment-history rows, with timeline_total). verified_status is the label stored with each reference: verified for a Metasploit module, for an Exploit-DB entry Exploit-DB marks verified, and for curated seed rows marked so; reported for a public artefact nothing has confirmed works (nuclei templates, GitHub proofs of concept, unverified Exploit-DB entries); unconfirmed where a curated row says so. It is a label from the source, not a guarantee that the exploit works against a given system. An empty exploits list is not evidence that no public exploit exists: it covers only the sources EchelonGraph ingests, and which of them are polled depends on the deployment. A section the API could not read is named in coverage.sections_failed and left out of data, never relayed as an empty list. Vendor advisories, patches, generated summaries, trending signals and historical incidents are not relayed. Pass a CVE ID like CVE-2021-44228. Its structured result carries state (measured), measured_at (null: each row carries its own time), method, coverage (the sections relayed, failed and left out, and per-list counts), freshness (null) and notes, with data equal to the first text block; the result's last text block repeats it without data and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cve_id": {
"description": "a CVE ID, e.g. CVE-2021-44228",
"type": "string"
}
},
"required": [
"cve_id"
],
"type": "object"
},
"name": "cve_intel",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"affected_packages": {
"additionalProperties": false,
"properties": {
"api_row_limit": {
"description": "The most rows the API returns for this list per CVE: a list this long may be cut.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"returned": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Rows the API returned; null when the section was not read."
}
},
"required": [
"returned",
"api_row_limit"
],
"type": "object"
},
"exploits": {
"additionalProperties": false,
"properties": {
"api_row_limit": {
"description": "The most rows the API returns for this list per CVE: a list this long may be cut.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"returned": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Rows the API returned; null when the section was not read."
}
},
"required": [
"returned",
"api_row_limit"
],
"type": "object"
},
"fixed_versions": {
"additionalProperties": false,
"properties": {
"api_row_limit": {
"description": "The most rows the API returns for this list per CVE: a list this long may be cut.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"returned": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Rows the API returned; null when the section was not read."
}
},
"required": [
"returned",
"api_row_limit"
],
"type": "object"
},
"sections_failed": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The sections the API says it could not read (its failed_sections), left out of data; null when the answer does not say (an API older than failed_sections), so an empty list may be an unread section."
},
"sections_left_out": {
"description": "The sections of the answer this tool does not relay.",
"items": {
"type": "string"
},
"type": "array"
},
"sections_relayed": {
"description": "The sections of the answer relayed in data.",
"items": {
"type": "string"
},
"type": "array"
},
"timeline": {
"additionalProperties": false,
"properties": {
"api_row_limit": {
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"relayed": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The newest rows relayed in data.timeline."
},
"returned": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
]
}
},
"required": [
"returned",
"relayed",
"api_row_limit"
],
"type": "object"
}
},
"required": [
"sections_relayed",
"sections_failed",
"sections_left_out",
"exploits",
"affected_packages",
"fixed_versions",
"timeline"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": false,
"properties": {
"affected_packages": {
"items": {
"additionalProperties": {},
"properties": {
"dependents_count": {
"type": [
"number",
"null"
]
},
"ecosystem": {
"type": [
"string",
"null"
]
},
"fixed_version": {
"type": [
"string",
"null"
]
},
"package_name": {
"type": [
"string",
"null"
]
},
"source": {
"type": [
"string",
"null"
]
},
"version_range": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"cve_id": {
"type": "string"
},
"cwes": {
"items": {
"additionalProperties": {},
"properties": {
"cwe_id": {
"type": [
"string",
"null"
]
},
"name": {
"type": [
"string",
"null"
]
},
"source": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"exploits": {
"items": {
"additionalProperties": {},
"properties": {
"description": {
"type": [
"string",
"null"
]
},
"first_seen_at": {
"type": [
"string",
"null"
]
},
"kind": {
"description": "metasploit, exploit_db, nuclei_template, github_poc or vendor_poc.",
"type": [
"string",
"null"
]
},
"source_name": {
"type": [
"string",
"null"
]
},
"source_url": {
"type": [
"string",
"null"
]
},
"verified_status": {
"description": "verified_status is the label stored with each reference: verified for a Metasploit module, for an Exploit-DB entry Exploit-DB marks verified, and for curated seed rows marked so; reported for a public artefact nothing has confirmed works (nuclei templates, GitHub proofs of concept, unverified Exploit-DB entries); unconfirmed where a curated row says so. It is a label from the source, not a guarantee that the exploit works against a given system.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"exploits_by_kind": {
"additionalProperties": {
"type": "number"
},
"propertyNames": {
"type": "string"
},
"type": "object"
},
"exploits_by_status": {
"additionalProperties": {
"type": "number"
},
"propertyNames": {
"type": "string"
},
"type": "object"
},
"exploits_capped": {
"description": "true: exploits lists fewer references than exploits_total.",
"type": "boolean"
},
"exploits_total": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Every exploit reference on record for the CVE, not only those listed in exploits."
},
"fixed_versions": {
"items": {
"additionalProperties": {},
"properties": {
"ecosystem": {
"type": [
"string",
"null"
]
},
"fixed_version": {
"type": [
"string",
"null"
]
},
"package_name": {
"type": [
"string",
"null"
]
},
"source": {
"type": [
"string",
"null"
]
},
"vulnerable_range": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"timeline": {
"items": {
"additionalProperties": {},
"properties": {
"enriched_at": {
"type": [
"string",
"null"
]
},
"enrichment_kind": {
"type": [
"string",
"null"
]
},
"fields_changed": {},
"score_delta": {
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"timeline_count_30d": {
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"timeline_count_7d": {
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"timeline_total": {
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
}
},
"required": [
"cve_id"
],
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"affected_packages": {
"additionalProperties": false,
"properties": {
"api_row_limit": {
"description": "The most rows the API returns for this list per CVE: a list this long may be cut.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"returned": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Rows the API returned; null when the section was not read."
}
},
"required": [
"returned",
"api_row_limit"
],
"type": "object"
},
"exploits": {
"additionalProperties": false,
"properties": {
"api_row_limit": {
"description": "The most rows the API returns for this list per CVE: a list this long may be cut.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"returned": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Rows the API returned; null when the section was not read."
}
},
"required": [
"returned",
"api_row_limit"
],
"type": "object"
},
"fixed_versions": {
"additionalProperties": false,
"properties": {
"api_row_limit": {
"description": "The most rows the API returns for this list per CVE: a list this long may be cut.",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"returned": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Rows the API returned; null when the section was not read."
}
},
"required": [
"returned",
"api_row_limit"
],
"type": "object"
},
"sections_failed": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The sections the API says it could not read (its failed_sections), left out of data; null when the answer does not say (an API older than failed_sections), so an empty list may be an unread section."
},
"sections_left_out": {
"description": "The sections of the answer this tool does not relay.",
"items": {
"type": "string"
},
"type": "array"
},
"sections_relayed": {
"description": "The sections of the answer relayed in data.",
"items": {
"type": "string"
},
"type": "array"
},
"timeline": {
"additionalProperties": false,
"properties": {
"api_row_limit": {
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"relayed": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The newest rows relayed in data.timeline."
},
"returned": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
]
}
},
"required": [
"returned",
"relayed",
"api_row_limit"
],
"type": "object"
}
},
"required": [
"sections_relayed",
"sections_failed",
"sections_left_out",
"exploits",
"affected_packages",
"fixed_versions",
"timeline"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "Summary of EchelonGraph's CVE Pulse feed: summary.total active CVEs, their counts by severity band (summary.critical, summary.high, summary.medium, summary.low), the count with no band (summary.none), and summary.last_updated, the newest modification time among those records. summary.none is not a severity rating of None: it counts the active CVEs with no severity band from any source, that is, CVEs not yet scored, and the answer may carry the same count again as summary.unscored. Whenever summary.none is above zero the note says so: report those CVEs as not yet scored, not as CVEs rated None. summary.nvd_critical, summary.nvd_high, summary.nvd_medium, summary.nvd_low and summary.nvd_none count the same active CVEs as summary.total by NVD's CVSS severity label (v3.x, else v4.0; before NVD's record arrives, or where it gives none, a pre-NVD label from the CVE.org record or a GitHub advisory can stand in): provenance, never EchelonGraph's severity band. summary.nvd_none counts the active CVEs with no Critical, High, Medium or Low label there, CVEs NVD never labelled under CVSS v3 among them, and many of those carry an NVD CVSS v2 score instead: it is neither a count of CVEs rated None nor the count of CVEs with no severity, which is summary.none. Whenever summary.nvd_none is above zero the note says what it counts, with its count. summary.rejected counts the CVE records rejected (withdrawn) by their numbering authority, which summary.total and the other counts above leave out: report them as withdrawn records, never as vulnerabilities. The feed is polled from its sources on a schedule, so this is the state as of that update. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the feed serves no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "cve_summary",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"description": "What the answer covers; null where the answer says nothing about it.",
"type": "null"
},
"data": {
"additionalProperties": {},
"properties": {
"summary": {
"additionalProperties": {},
"properties": {
"critical": {
"type": [
"number",
"null"
]
},
"high": {
"type": [
"number",
"null"
]
},
"last_updated": {
"type": [
"string",
"null"
]
},
"low": {
"type": [
"number",
"null"
]
},
"medium": {
"type": [
"number",
"null"
]
},
"none": {
"description": "The active CVEs with no severity band from any source: CVEs not yet scored, not a severity rating of None.",
"type": [
"number",
"null"
]
},
"nvd_critical": {
"description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Critical: NVD's label, as provenance, never EchelonGraph's severity band.",
"type": [
"number",
"null"
]
},
"nvd_high": {
"description": "Of the active CVEs total counts, those whose NVD CVSS severity label is High: NVD's label, as provenance, never EchelonGraph's severity band.",
"type": [
"number",
"null"
]
},
"nvd_low": {
"description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Low: NVD's label, as provenance, never EchelonGraph's severity band.",
"type": [
"number",
"null"
]
},
"nvd_medium": {
"description": "Of the active CVEs total counts, those whose NVD CVSS severity label is Medium: NVD's label, as provenance, never EchelonGraph's severity band.",
"type": [
"number",
"null"
]
},
"nvd_none": {
"description": "Of the active CVEs total counts, those with no Critical, High, Medium or Low NVD CVSS severity label, many of them with an NVD CVSS v2 score instead: neither a count of CVEs rated None nor the count of CVEs with no severity, which is none.",
"type": [
"number",
"null"
]
},
"rejected": {
"description": "The CVE records rejected (withdrawn) by their numbering authority, which total and every other count here leave out: withdrawn records, never vulnerabilities.",
"type": [
"number",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
},
"unscored": {
"description": "The same count as none, under its own name.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"type": "null"
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "How one CVE's EPSS score (FIRST's exploit-prediction probability, 0 to 1, with its percentile) has changed, as EchelonGraph recorded it: points, oldest first, each with at, epss_score and epss_percentile; current, the record's value now (epss_score, epss_percentile, epss_updated_at); series_kind, always change_only; series_starts_at, when EchelonGraph began recording EPSS changes for any CVE; history_rows, points_truncated and latest_point_matches_current. Pass a CVE ID like CVE-2023-44487. The series is change-only: a point is a recorded change, and a day without a point is not a recorded value. Never interpolate it into a daily series. Before series_starts_at nothing was recorded, so a missing point there means not recorded, not unchanged, and the value in force before a CVE's first point is not in the series. latest_point_matches_current false means a change is missing from the series. Its structured result carries state (measured), measured_at (current.epss_updated_at: when EchelonGraph last wrote a changed value, not FIRST's score date), method, coverage (series_kind, series_starts_at, points, points_truncated), freshness (null) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cve_id": {
"description": "a CVE ID, e.g. CVE-2023-44487",
"type": "string"
}
},
"required": [
"cve_id"
],
"type": "object"
},
"name": "epss_history",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"points": {
"description": "How many points the series holds.",
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"points_truncated": {
"type": "boolean"
},
"series_kind": {
"enum": [
"change_only"
],
"type": "string"
},
"series_starts_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"series_kind",
"series_starts_at",
"points",
"points_truncated"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": {},
"properties": {
"current": {
"additionalProperties": {},
"properties": {
"epss_percentile": {
"type": [
"number",
"null"
]
},
"epss_score": {
"description": "The record's EPSS probability now; null when it holds none.",
"type": [
"number",
"null"
]
},
"epss_updated_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When EchelonGraph last wrote a changed EPSS value for this CVE."
}
},
"type": "object"
},
"cve_id": {
"type": "string"
},
"history_rows": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Raw history rows read, before repeated records of one change were collapsed."
},
"latest_point_matches_current": {
"description": "Whether the newest point equals current; false means a change is missing from the series; null when there is no point or no current value.",
"type": [
"boolean",
"null"
]
},
"points": {
"description": "Recorded changes, oldest first. Never a daily series.",
"items": {
"additionalProperties": {},
"properties": {
"at": {
"description": "When EchelonGraph recorded this change.",
"type": "string"
},
"epss_percentile": {
"description": "Its percentile (0 to 1), null where the record held none.",
"type": [
"number",
"null"
]
},
"epss_score": {
"description": "The EPSS probability (0 to 1) from that change on.",
"type": "number"
}
},
"required": [
"at",
"epss_score"
],
"type": "object"
},
"type": "array"
},
"points_truncated": {
"description": "True when only the newest rows were read, so the earliest points are missing.",
"type": [
"boolean",
"null"
]
},
"series_kind": {
"description": "Always change_only: one point per recorded change, none for a day without one.",
"enum": [
"change_only"
],
"type": "string"
},
"series_starts_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "The earliest EPSS change EchelonGraph recorded for any CVE: when recording began. Null when nothing has been recorded."
}
},
"required": [
"cve_id",
"series_kind",
"series_starts_at",
"current",
"points"
],
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"points": {
"description": "How many points the series holds.",
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"points_truncated": {
"type": "boolean"
},
"series_kind": {
"enum": [
"change_only"
],
"type": "string"
},
"series_starts_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"series_kind",
"series_starts_at",
"points",
"points_truncated"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "Aggregate totals from EchelonGraph's internet-exposure radars, each refreshed on its own schedule: internet-facing services running actively-exploited (CISA-KEV) CVEs, plus the ransomware-linked subset, derived from Shodan data; unauthenticated data stores and observability UIs, found through Shodan (LeakIX when Shodan query credits run low) and then confirmed by EchelonGraph's own identified check (not a pure read: on Redis it names its client, and on ClickHouse its query is recorded in the server's query log); leaked credentials sampled from public GitHub push events; and shadow AI services found through Certificate Transparency logs and Shodan and then checked by EchelonGraph's identified probes. It also gives MCP-server counts: hostnames named like an MCP server in EchelonGraph's own Certificate Transparency feed (no Shodan data), each counted once by its latest verdict from EchelonGraph's identified MCP probe, which never sends tools/call. Every number in the result is labelled here and in the result's note by what it counts; a field this version cannot label is left out and named in the note. kev_exposure: kev_exposure.distinct_hosts counts distinct ip:port services, not machines (a machine answering on two ports counts twice), with at least one CISA-KEV-listed CVE on record, and kev_exposure.ransomware_hosts those with a ransomware-linked one; kev_exposure.kev_cves_exposed and kev_exposure.ransomware_cves count distinct CVEs with at least one such service; kev_exposure.correlations counts service×CVE pairs, not services, so a service with three KEV CVEs counts three times. kev_exposure.top_products, kev_exposure.top_countries and kev_exposure.top_cves rank up to 12 products, 10 countries and 12 CVEs by those services; kev_exposure.top_cves[].cvss_v3_score and kev_exposure.top_cves[].epss_score are the highest CVSS v3 base score and EPSS probability recorded on that CVE's observations. kev_exposure.trend counts service×CVE pairs still on record by the week in which each was first recorded, over 12 weeks, so earlier weeks read low. kev_exposure.newest_kev lists the 15 CVEs that EchelonGraph's CVE records most recently mark as CISA-KEV-listed, each with an exposure_state: exposed, where kev_exposure.newest_kev[].exposed_hosts counts distinct ip:port services on record with it; or not_assessed, where the API's answer holds no measurement for that CVE (its 0 is not one) and no count is relayed, and cve_exposure says per CVE whether the radar tracks it. kev_exposure.newest_kev[].cvss_v3_score and kev_exposure.newest_kev[].epss_score are the CVE record's CVSS v3 base score and EPSS probability. exposed_databases: exposed_databases.distinct_hosts counts distinct ip:port services the check confirmed answering without authentication, and exposed_databases.engines the distinct engine types among them; exposed_databases.top_engines and exposed_databases.top_countries rank up to 15 engines and 10 countries by those services. exposed_databases.pii_likely and exposed_databases.pci_likely count services whose schema names (never record values) pass a high-confidence, precision-first gate for personal or payment-card data, so a service outside them is not shown to hold no such data. leaked_credentials: leaked_credentials.total counts (repository, secret) pairs, not distinct secrets, so one secret in three repositories counts three times; leaked_credentials.distinct_secrets counts each secret once and leaked_credentials.distinct_repos counts repositories; leaked_credentials.top_providers and leaked_credentials.top_types rank up to 15 providers and secret types by those pairs. None is validated: each is a credential-shaped string that passed EchelonGraph's filters, at most structurally checked and never tested against its provider. Each of those three radars also carries generated_at, when the API computed its totals, and, when the API can tell, last_run_at. kev_exposure.last_run_at, exposed_databases.last_run_at and leaked_credentials.last_run_at are timestamps, not counts: each is when that radar last completed a check, a cycle whose reads succeeded, among them a Shodan search (for exposed_databases, or its LeakIX fallback) that answered at least one query, or for leaked_credentials a read of the public GitHub event stream. A cycle that read nothing does not move it, and it is not the time of every record a radar's numbers count, which cover everything still on record, not only what the last check found. A radar whose answer carries no last_run_at has none in the result, and the note says nothing about it. shadow_ai: the result is regrouped by what each number counts. shadow_ai.confirmed_exposed counts services EchelonGraph's probes found answering without an authentication gate (liveness active, or rechecking during a re-check): confirmed_exposed.total is the sum of confirmed_exposed.by_category, and confirmed_exposed.last_24h counts those first recorded in the last 24 h. Of the shadow_ai numbers, only confirmed_exposed counts exposed services. shadow_ai.observed counts every Certificate Transparency or Shodan observation on record, whatever its verification state: its numbers are observed, not exposed. They are observed.total; observed.by_category (the same observations by category); observed.last_24h (those first recorded in the last 24 h); observed.trend_30d (observations per UTC day over the last 30 days); and observed.top_products, observed.top_countries and observed.top_issuers (up to ten products, countries and issuers ranked by observations, where an issuer is the certificate's CA for a Certificate Transparency observation and the hosting operator Shodan reports for a Shodan one). shadow_ai.authentication counts observations by probe outcome: authentication.observed where a probe observed an authentication gate (a 401/403, a login page or an auth marker), and authentication.not_determined where the service answered but no probe could tell. Neither authentication count is part of confirmed_exposed, and observed.total minus confirmed_exposed.total is not a count of secured services. The shadow-AI poller block carries only running and last_run_at: last_run_at is when the radar's leader last completed a Certificate Transparency (crt.sh) cycle, and its running is true only when that was within 30 minutes of the answer. mcp_servers: counts and timestamps only, no hostname. mcp_servers.total counts hostnames the AI-exposure radar has checked for an MCP server, each once by its latest verdict on record, and not every one is an MCP server; EchelonGraph's own control servers are left out, and mcp_servers.own_controls_excluded counts them. mcp_servers.total is mcp_servers.protected plus mcp_servers.pending_readjudication plus mcp_servers.not_assessed. mcp_servers.protected counts hostnames whose /mcp endpoint asked for credentials and whose OAuth protected-resource metadata validated under RFC 9728; mcp_servers.prm_via divides them by where that document was found: mcp_servers.prm_via.header, mcp_servers.prm_via.wellknown_path and mcp_servers.prm_via.wellknown_root. mcp_servers.pending_readjudication counts verdicts of a rule since replaced, not yet re-checked. mcp_servers.not_assessed counts the rest, whose protection the radar could not assess (not assessed does not mean unprotected), and mcp_servers.not_assessed_by_reason puts each in one bucket. mcp_servers.not_assessed_by_reason.identified_no_challenge holds servers that identified themselves as MCP servers and did not ask for credentials at the handshake. That is normal in MCP: authorization is optional in the spec, and a server can enforce it at tools/call instead, which EchelonGraph never sends, so this bucket is not a finding of exposure. mcp_servers.not_assessed_by_reason.resource_mismatch, mcp_servers.not_assessed_by_reason.cross_origin_pointer, mcp_servers.not_assessed_by_reason.bare_challenge_no_prm, mcp_servers.not_assessed_by_reason.pointer_unreachable, mcp_servers.not_assessed_by_reason.pointer_invalid, mcp_servers.not_assessed_by_reason.no_authorization_servers, mcp_servers.not_assessed_by_reason.wellknown_unreachable and mcp_servers.not_assessed_by_reason.metadata_invalid hold endpoints that asked for credentials but whose RFC 9728 metadata did not validate, by why, so none of them is shown to lack protection; mcp_servers.not_assessed_by_reason.challenge_unadjudicated holds endpoints that asked for credentials before that check existed, not yet re-checked. mcp_servers.not_assessed_by_reason.no_http_answer holds hostnames that gave no HTTP answer, and mcp_servers.not_assessed_by_reason.not_identified_as_mcp hostnames whose HTTP answer identified no MCP server. mcp_servers.era divides every counted hostname by protocol era: mcp_servers.era.legacy; mcp_servers.era.dual, a lower bound; mcp_servers.era.modern, not proven modern-only; mcp_servers.era.unknown; and mcp_servers.era.not_measured, recorded before the era probe and not re-checked since. mcp_servers.transport divides them by transport: mcp_servers.transport.streamable_http, mcp_servers.transport.legacy_sse, mcp_servers.transport.unknown and mcp_servers.transport.not_measured. mcp_servers.window.from and mcp_servers.window.to are when the oldest and the newest of the verdicts counted were last checked. mcp_servers.last_run_at is a timestamp, not a count: when the AI-exposure radar, which checks other AI services too, last completed a check; mcp_servers.enabled is whether one completed within 45 minutes of the answer, and mcp_servers.counted_at is when the API read the counts. A partition whose buckets do not add up to the count it divides is left out and named; an answer that does not say it is the MCP-server counts, or whose mcp_servers.total, mcp_servers.protected, mcp_servers.pending_readjudication and mcp_servers.not_assessed are missing or contradict each other, is a failure. Shodan data is owned by Shodan, which holds its copyright (© Shodan). Its structured result's state is not_assessed with measured_at null: every radar answered, but none gives one time at which what it counts was observed (mcp_servers dates its verdicts at most by a window, mcp_servers.window), so no count is presented as a dated measurement; each count is still relayed, labelled, as what that radar holds on record. freshness gives each radar's last_run_at (and running for shadow_ai, enabled for mcp_servers) where the API serves one; coverage names the radars that answered; data is the relayed result above. The result's last text block repeats the structured result without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "exposure_radar",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"answered": {
"description": "The radars that answered. On a failure their answers are withheld.",
"items": {
"type": "string"
},
"type": "array"
},
"failed": {
"description": "The radars that could not be read.",
"items": {
"type": "string"
},
"type": "array"
},
"radars": {
"description": "The radars this tool reads.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"radars",
"answered",
"failed"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": false,
"properties": {
"exposed_databases": {
"additionalProperties": false,
"properties": {
"distinct_hosts": {
"type": "number"
},
"engines": {
"type": "number"
},
"generated_at": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"last_run_at": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"pci_likely": {
"type": "number"
},
"pii_likely": {
"type": "number"
},
"top_countries": {
"items": {
"additionalProperties": false,
"properties": {
"country": {
"type": "string"
},
"hosts": {
"type": "number"
}
},
"required": [
"country",
"hosts"
],
"type": "object"
},
"type": "array"
},
"top_engines": {
"items": {
"additionalProperties": false,
"properties": {
"engine": {
"type": "string"
},
"hosts": {
"type": "number"
}
},
"required": [
"engine",
"hosts"
],
"type": "object"
},
"type": "array"
}
},
"type": "object"
},
"kev_exposure": {
"additionalProperties": false,
"properties": {
"correlations": {
"type": "number"
},
"distinct_hosts": {
"type": "number"
},
"generated_at": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"kev_cves_exposed": {
"type": "number"
},
"last_run_at": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"newest_kev": {
"items": {
"additionalProperties": false,
"properties": {
"added_date": {
"type": "string"
},
"cve_id": {
"type": "string"
},
"cvss_v3_score": {
"type": "number"
},
"epss_score": {
"type": "number"
},
"exposed_hosts": {
"type": "number"
},
"exposure_state": {
"enum": [
"exposed",
"measured_zero",
"not_assessed"
],
"type": "string"
},
"ransomware": {
"type": "boolean"
},
"severity": {
"type": "string"
},
"vuln_name": {
"type": "string"
}
},
"required": [
"cve_id",
"exposure_state"
],
"type": "object"
},
"type": "array"
},
"ransomware_cves": {
"type": "number"
},
"ransomware_hosts": {
"type": "number"
},
"top_countries": {
"items": {
"additionalProperties": false,
"properties": {
"country": {
"type": "string"
},
"hosts": {
"type": "number"
}
},
"required": [
"country",
"hosts"
],
"type": "object"
},
"type": "array"
},
"top_cves": {
"items": {
"additionalProperties": false,
"properties": {
"cve_id": {
"type": "string"
},
"cvss_v3_score": {
"type": "number"
},
"epss_score": {
"type": "number"
},
"hosts": {
"type": "number"
},
"ransomware": {
"type": "boolean"
},
"severity": {
"type": "string"
}
},
"required": [
"cve_id",
"hosts"
],
"type": "object"
},
"type": "array"
},
"top_products": {
"items": {
"additionalProperties": false,
"properties": {
"hosts": {
"type": "number"
},
"product": {
"type": "string"
}
},
"required": [
"product",
"hosts"
],
"type": "object"
},
"type": "array"
},
"trend": {
"items": {
"additionalProperties": false,
"properties": {
"new_exposures": {
"type": "number"
},
"week": {
"type": "string"
}
},
"required": [
"week",
"new_exposures"
],
"type": "object"
},
"type": "array"
}
},
"type": "object"
},
"leaked_credentials": {
"additionalProperties": false,
"properties": {
"distinct_repos": {
"type": "number"
},
"distinct_secrets": {
"type": "number"
},
"generated_at": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"last_run_at": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"top_providers": {
"items": {
"additionalProperties": false,
"properties": {
"count": {
"type": "number"
},
"provider": {
"type": "string"
}
},
"required": [
"provider",
"count"
],
"type": "object"
},
"type": "array"
},
"top_types": {
"items": {
"additionalProperties": false,
"properties": {
"count": {
"type": "number"
},
"secret_type": {
"type": "string"
}
},
"required": [
"secret_type",
"count"
],
"type": "object"
},
"type": "array"
},
"total": {
"type": "number"
}
},
"type": "object"
},
"mcp_servers": {
"additionalProperties": false,
"properties": {
"counted_at": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"enabled": {
"type": "boolean"
},
"era": {
"additionalProperties": false,
"properties": {
"dual": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"legacy": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"modern": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"not_measured": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"unknown": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
}
},
"required": [
"legacy",
"dual",
"modern",
"unknown",
"not_measured"
],
"type": "object"
},
"last_run_at": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"not_assessed": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"not_assessed_by_reason": {
"additionalProperties": false,
"properties": {
"bare_challenge_no_prm": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"challenge_unadjudicated": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"cross_origin_pointer": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"identified_no_challenge": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"metadata_invalid": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"no_authorization_servers": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"no_http_answer": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"not_identified_as_mcp": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"pointer_invalid": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"pointer_unreachable": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"resource_mismatch": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"wellknown_unreachable": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
}
},
"required": [
"identified_no_challenge",
"resource_mismatch",
"cross_origin_pointer",
"bare_challenge_no_prm",
"pointer_unreachable",
"pointer_invalid",
"no_authorization_servers",
"wellknown_unreachable",
"metadata_invalid",
"challenge_unadjudicated",
"no_http_answer",
"not_identified_as_mcp"
],
"type": "object"
},
"own_controls_excluded": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"pending_readjudication": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"prm_via": {
"additionalProperties": false,
"properties": {
"header": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"wellknown_path": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"wellknown_root": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
}
},
"required": [
"header",
"wellknown_path",
"wellknown_root"
],
"type": "object"
},
"protected": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"total": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"transport": {
"additionalProperties": false,
"properties": {
"legacy_sse": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"not_measured": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"streamable_http": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"unknown": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
}
},
"required": [
"streamable_http",
"legacy_sse",
"unknown",
"not_measured"
],
"type": "object"
},
"window": {
"additionalProperties": false,
"properties": {
"from": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"to": {
"description": "An RFC 3339 instant.",
"type": "string"
}
},
"required": [
"from",
"to"
],
"type": "object"
}
},
"required": [
"total",
"protected",
"pending_readjudication",
"not_assessed"
],
"type": "object"
},
"shadow_ai": {
"additionalProperties": false,
"properties": {
"authentication": {
"additionalProperties": false,
"properties": {
"not_determined": {
"type": "number"
},
"observed": {
"type": "number"
}
},
"type": "object"
},
"confirmed_exposed": {
"additionalProperties": false,
"properties": {
"by_category": {
"additionalProperties": {
"type": "number"
},
"propertyNames": {
"type": "string"
},
"type": "object"
},
"last_24h": {
"type": "number"
},
"total": {
"type": "number"
}
},
"type": "object"
},
"observed": {
"additionalProperties": false,
"properties": {
"by_category": {
"additionalProperties": {
"type": "number"
},
"propertyNames": {
"type": "string"
},
"type": "object"
},
"last_24h": {
"type": "number"
},
"last_observation": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"top_countries": {
"items": {
"additionalProperties": false,
"properties": {
"count": {
"type": "number"
},
"country": {
"type": "string"
}
},
"required": [
"country",
"count"
],
"type": "object"
},
"type": "array"
},
"top_issuers": {
"items": {
"additionalProperties": false,
"properties": {
"count": {
"type": "number"
},
"issuer": {
"type": "string"
}
},
"required": [
"issuer",
"count"
],
"type": "object"
},
"type": "array"
},
"top_products": {
"items": {
"additionalProperties": false,
"properties": {
"count": {
"type": "number"
},
"product": {
"type": "string"
}
},
"required": [
"product",
"count"
],
"type": "object"
},
"type": "array"
},
"total": {
"type": "number"
},
"trend_30d": {
"items": {
"additionalProperties": false,
"properties": {
"count": {
"type": "number"
},
"date": {
"type": "string"
}
},
"required": [
"date",
"count"
],
"type": "object"
},
"type": "array"
}
},
"type": "object"
},
"poller": {
"additionalProperties": false,
"properties": {
"last_run_at": {
"description": "An RFC 3339 instant.",
"type": "string"
},
"running": {
"type": "boolean"
}
},
"required": [
"running",
"last_run_at"
],
"type": "object"
}
},
"type": "object"
}
},
"required": [
"kev_exposure",
"exposed_databases",
"leaked_credentials",
"shadow_ai",
"mcp_servers"
],
"type": "object"
},
"freshness": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"exposed_databases": {
"additionalProperties": false,
"properties": {
"last_run_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"last_run_at"
],
"type": "object"
},
"kev_exposure": {
"additionalProperties": false,
"properties": {
"last_run_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"last_run_at"
],
"type": "object"
},
"leaked_credentials": {
"additionalProperties": false,
"properties": {
"last_run_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"last_run_at"
],
"type": "object"
},
"mcp_servers": {
"additionalProperties": false,
"properties": {
"enabled": {
"type": [
"boolean",
"null"
]
},
"last_run_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"last_run_at",
"enabled"
],
"type": "object"
},
"shadow_ai": {
"additionalProperties": false,
"properties": {
"last_run_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
]
},
"running": {
"type": [
"boolean",
"null"
]
}
},
"required": [
"last_run_at",
"running"
],
"type": "object"
}
},
"required": [
"kev_exposure",
"exposed_databases",
"leaked_credentials",
"shadow_ai",
"mcp_servers"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "The producing radar's last completed check (last_run_at), where the API serves one."
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"answered": {
"description": "The radars that answered. On a failure their answers are withheld.",
"items": {
"type": "string"
},
"type": "array"
},
"failed": {
"description": "The radars that could not be read.",
"items": {
"type": "string"
},
"type": "array"
},
"radars": {
"description": "The radars this tool reads.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"radars",
"answered",
"failed"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"radars": {
"description": "Each radar that could not be read, and why.",
"items": {
"additionalProperties": false,
"properties": {
"kind": {
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"unexpected_shape"
],
"type": "string"
},
"message": {
"type": "string"
},
"path": {
"type": "string"
},
"radar": {
"type": "string"
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
]
}
},
"required": [
"radar",
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"type": "array"
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "Full record for one CVE: description, severity, cvss_v3_score, cvss_v4_score and cvss_v4_severity (when the record has a CVSS v4 score), echelongraph_score and echelongraph_severity with score_confidence (EchelonGraph's multi-source score) and score_assessed (whether EchelonGraph has scored it), epss_score and epss_percentile, CISA-KEV status (kev_listed, kev_added_date, and kev_ransomware for known ransomware-campaign use), ghsa_id (GitHub GHSA), references, cpe_match (the CPE criteria as one flat list) and cpe_configurations (NVD's configurations as NVD sent them, with each AND/OR operator, negate, versionStartExcluding and matchCriteriaId; absent where EchelonGraph has stored none, which is not a finding that no product is affected), published, modified and updated_at; each field only where the record has it. Pass a CVE ID like CVE-2023-44487. echelongraph_score, echelongraph_severity and echelongraph_risk are EchelonGraph's score only when score_assessed is true. With score_assessed false the CVE is NOT YET SCORED, not scored 0: any of those three it carries (0, NONE, 0) is a placeholder, not a rating, and does not mean the CVE is harmless; the API may leave them out instead, score_confidence is NONE, and score_unassessed_reason says why (a rejected record, withdrawn by its numbering authority, is never scored, and the note says NOT SCORED). The note labels each such CVE NOT YET SCORED: report it that way, never as a score of 0. An answer with no score_assessed (an API older than that field) does not say whether the CVE was scored, the note says so, and a 0 there is not a rating either. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the feed serves no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cve_id": {
"description": "a CVE ID, e.g. CVE-2023-44487",
"type": "string"
}
},
"required": [
"cve_id"
],
"type": "object"
},
"name": "get_cve",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"description": "What the answer covers; null where the answer says nothing about it.",
"type": "null"
},
"data": {
"additionalProperties": {},
"properties": {
"cpe_configurations": {
"anyOf": [
{
"items": {},
"type": "array"
},
{
"type": "null"
}
],
"description": "NVD's configurations array as NVD sent it: each configuration and node with its operator (AND, OR) and negate, and each cpeMatch with criteria, vulnerable, versionStartIncluding, versionStartExcluding, versionEndIncluding, versionEndExcluding and matchCriteriaId. A cpeMatch with vulnerable false inside an AND configuration is the platform the vulnerable product runs on, not an affected product. Absent: EchelonGraph holds no stored NVD configuration for the CVE, which is not a finding that no product is affected."
},
"cpe_match": {
"description": "The record's CPE match criteria as one flat list, every configuration's cpeMatch entries together: the AND/OR operator and negate of each configuration and node, versionStartExcluding and matchCriteriaId are not in it, so a CPE that is only a platform a product runs on reads as one more entry."
},
"cve_id": {
"type": [
"string",
"null"
]
},
"cvss_v3_score": {
"type": [
"number",
"null"
]
},
"cvss_v4_score": {
"type": [
"number",
"null"
]
},
"cvss_v4_severity": {
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"echelongraph_risk": {
"description": "EchelonGraph's 0-100 risk priority, fused from the score, exploitation and automatability: a rating only when score_assessed is true. With score_assessed false it is a placeholder.",
"type": [
"number",
"null"
]
},
"echelongraph_score": {
"description": "EchelonGraph's 0-10 score for the CVE: a score only when score_assessed is true. With score_assessed false it is a placeholder, not a rating.",
"type": [
"number",
"null"
]
},
"echelongraph_severity": {
"description": "The severity band of echelongraph_score: a rating only when score_assessed is true. With score_assessed false it is a placeholder (NONE).",
"type": [
"string",
"null"
]
},
"epss_percentile": {
"type": [
"number",
"null"
]
},
"epss_score": {
"type": [
"number",
"null"
]
},
"ghsa_id": {
"type": [
"string",
"null"
]
},
"kev_added_date": {
"type": [
"string",
"null"
]
},
"kev_listed": {
"type": [
"boolean",
"null"
]
},
"kev_ransomware": {
"type": [
"boolean",
"null"
]
},
"modified": {
"type": [
"string",
"null"
]
},
"published": {
"type": [
"string",
"null"
]
},
"references": {},
"score_assessed": {
"description": "Whether EchelonGraph has scored the CVE. true: echelongraph_score, echelongraph_severity and echelongraph_risk are its score. false: the CVE is NOT YET SCORED, not scored 0, and any of those three it carries is a placeholder, not a rating; the API may leave them out. Absent (an API older than the field): the answer does not say whether the CVE was scored.",
"type": [
"boolean",
"null"
]
},
"score_confidence": {
"type": [
"string",
"null"
]
},
"score_unassessed_reason": {
"description": "Why score_assessed is false: no_signal, no source has yet published severity data EchelonGraph can score; or rejected, the record was withdrawn by its numbering authority and is never scored. Absent when the CVE is scored.",
"type": [
"string",
"null"
]
},
"severity": {
"type": [
"string",
"null"
]
},
"updated_at": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"type": "null"
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "One CWE (weakness class) and the CVEs classified under it. Returns cwe_id, name and description (from the MITRE CWE catalog EchelonGraph embeds, version catalog_version), total (the active CVEs in EchelonGraph's feed that an NVD, GitHub or CVE.org record classifies under it, rejected and reserved records left out), and cves, one page of 50: each with cve_id, severity, cvss_v3_score, echelongraph_score, echelongraph_severity, score_assessed, kev_listed, published and a shortened description. order says how the rows are sorted (CISA-KEV-listed first, then EchelonGraph score); an answer without order does not state its order, and the note says so. page is the page served, page_size its size and max_page the last page the API serves: a later page is answered as max_page, so past max_page pages total counts CVEs no page lists. echelongraph_score is EchelonGraph's score only when score_assessed is true; the note labels each row that is NOT YET SCORED. A total of 0 says that no CVE in EchelonGraph's feed is classified under that CWE, not that none exists. Pass cwe_id like CWE-79 (or 79) and an optional page (1-200). Its structured result carries state (measured), measured_at (null), method, coverage (total, returned, page, page_requested, page_size, max_page), freshness (null) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cwe_id": {
"description": "a CWE ID, e.g. CWE-79 (or 79)",
"type": "string"
},
"page": {
"description": "page of 50 CVEs (default 1, max 200)",
"maximum": 200,
"minimum": 1,
"type": "integer"
}
},
"required": [
"cwe_id"
],
"type": "object"
},
"name": "get_cwe",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"max_page": {
"type": [
"number",
"null"
]
},
"page": {
"description": "The page served.",
"type": [
"number",
"null"
]
},
"page_requested": {
"description": "The page asked for.",
"type": "number"
},
"page_size": {
"type": [
"number",
"null"
]
},
"returned": {
"type": [
"number",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
}
},
"required": [
"total",
"returned",
"page",
"page_requested",
"page_size",
"max_page"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": {},
"properties": {
"catalog_version": {
"description": "The version of the MITRE CWE catalog name and description come from.",
"type": [
"string",
"null"
]
},
"cves": {
"items": {
"additionalProperties": {},
"properties": {
"cve_id": {
"type": [
"string",
"null"
]
},
"cvss_v2_score": {
"type": [
"number",
"null"
]
},
"cvss_v2_severity": {
"type": [
"string",
"null"
]
},
"cvss_v3_score": {
"type": [
"number",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"echelongraph_score": {
"description": "EchelonGraph's 0-10 score: a score only when score_assessed is true.",
"type": [
"number",
"null"
]
},
"echelongraph_severity": {
"type": [
"string",
"null"
]
},
"kev_listed": {
"type": [
"boolean",
"null"
]
},
"published": {
"type": [
"string",
"null"
]
},
"score_assessed": {
"description": "Whether EchelonGraph has scored the CVE; false: NOT YET SCORED, not scored 0.",
"type": [
"boolean",
"null"
]
},
"severity": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"cwe_id": {
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"max_page": {
"description": "The last page the API serves; a later page is answered as this one.",
"type": [
"number",
"null"
]
},
"name": {
"type": [
"string",
"null"
]
},
"order": {
"description": "How cves is sorted, as the API states it; absent from an API older than the field, which sorted by CVE id.",
"type": [
"string",
"null"
]
},
"page": {
"type": [
"number",
"null"
]
},
"page_size": {
"type": [
"number",
"null"
]
},
"total": {
"description": "The active CVEs classified under the CWE, rejected and reserved records left out.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"max_page": {
"type": [
"number",
"null"
]
},
"page": {
"description": "The page served.",
"type": [
"number",
"null"
]
},
"page_requested": {
"description": "The page asked for.",
"type": "number"
},
"page_size": {
"type": [
"number",
"null"
]
},
"returned": {
"type": [
"number",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
}
},
"required": [
"total",
"returned",
"page",
"page_requested",
"page_size",
"max_page"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "One vendor advisory in full, by vendor and the vendor's advisory ID (the vendor and vendor_advisory_id fields of a row from search_vendor_advisories or vendor_advisories_for_cve): title, description, severity, cvss_v3_score, cve_ids and known_cve_ids (those with a record in EchelonGraph's CVE feed), affected_products, remediation, references, vendor_modified_at, and withdrawn_at and withdrawn_reason when the vendor withdrew it. Each advisory carries vendor_published_at (the vendor's date), our_first_seen_at (when EchelonGraph first recorded it) and withdrawn (true: the vendor rescinded it; the note names each such advisory). measured_at is our_first_seen_at. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the answer carries no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"advisory_id": {
"description": "the vendor's advisory ID, e.g. RHSA-2024:1234 or GHSA-xxxx-xxxx-xxxx",
"type": "string"
},
"vendor": {
"description": "the vendor slug, e.g. microsoft, redhat, github",
"type": "string"
}
},
"required": [
"vendor",
"advisory_id"
],
"type": "object"
},
"name": "get_vendor_advisory",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"description": "What the answer covers; null where the answer says nothing about it.",
"type": "null"
},
"data": {
"additionalProperties": {},
"properties": {
"advisory_id": {
"type": [
"string",
"null"
]
},
"affected_products": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
]
},
"cve_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
]
},
"cvss_v3_score": {
"type": [
"number",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"known_cve_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The CVE IDs of cve_ids that have a record in EchelonGraph's CVE feed."
},
"our_first_seen_at": {
"description": "When EchelonGraph first recorded the advisory; not the vendor's date.",
"type": [
"string",
"null"
]
},
"references": {},
"remediation": {
"type": [
"string",
"null"
]
},
"severity": {
"type": [
"string",
"null"
]
},
"summary": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"vendor": {
"type": [
"string",
"null"
]
},
"vendor_advisory_id": {
"type": [
"string",
"null"
]
},
"vendor_display_name": {
"type": [
"string",
"null"
]
},
"vendor_modified_at": {
"type": [
"string",
"null"
]
},
"vendor_published_at": {
"description": "The date the vendor gives for the advisory.",
"type": [
"string",
"null"
]
},
"withdrawn": {
"description": "true: the vendor withdrew (rescinded) this advisory; report it as withdrawn.",
"type": [
"boolean",
"null"
]
},
"withdrawn_at": {
"type": [
"string",
"null"
]
},
"withdrawn_reason": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"type": "null"
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "The CVEs CISA has added to its Known Exploited Vulnerabilities (KEV) catalog, newest first, from EchelonGraph's copy of that catalog, which polls CISA's feed every 5 minutes. Each row in kev gives cve_id, kev_added_date (CISA's dateAdded), kev_due_date, kev_vendor, kev_product, kev_vuln_name and kev_ransomware (known ransomware-campaign use), EchelonGraph's severity, cvss_v3_score, epss_score, epss_percentile and eg_kev_tier for the CVE, and our_first_seen_kev, when EchelonGraph's poller first recorded the CVE entering the catalog (null where no such record exists). Filter by since and until (YYYY-MM-DD, inclusive, on kev_added_date; an RFC 3339 timestamp, such as the kev_added_date 2024-04-12T00:00:00Z that CVE records carry, is read as its UTC date, and anything else is refused), ransomware, and vendor (an exact, case-insensitive match on kev_vendor); page with limit (1 to 200, default 50) and cursor, passing back the previous page's next_cursor with the same filters. Rows within one date are ordered by cve_id. total counts the CVEs matching the filters; kev_listed_total counts every CVE EchelonGraph holds as KEV-listed, and catalog.catalog_count is CISA's own count in the catalog last fetched, so a gap between the two is entries not yet in EchelonGraph's CVE table, which no page returns. CISA's requiredAction and shortDescription are not returned. Its structured result carries state (measured), measured_at (our last successful fetch of CISA's feed, null when the API does not give it), method, coverage (the CISA KEV catalog: total, returned, kev_listed_total, catalog_count, limit, has_more), freshness (last_successful_fetch_at, catalog_version, date_released) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cursor": {
"description": "next_cursor from the previous page",
"type": "string"
},
"limit": {
"description": "page size (default 50, max 200)",
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"ransomware": {
"description": "true: only CVEs with known ransomware-campaign use; false: only those without",
"type": "boolean"
},
"since": {
"description": "earliest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as its UTC date)",
"type": "string"
},
"until": {
"description": "latest kev_added_date to include, YYYY-MM-DD (an RFC 3339 timestamp is read as its UTC date)",
"type": "string"
},
"vendor": {
"description": "CISA vendorProject, an exact case-insensitive match, e.g. 'Microsoft'",
"type": "string"
}
},
"type": "object"
},
"name": "kev_recent",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"catalog": {
"const": "CISA KEV catalog",
"type": "string"
},
"catalog_count": {
"description": "CISA's own count, in the catalog last fetched.",
"type": [
"number",
"null"
]
},
"has_more": {
"description": "Whether next_cursor names a further page.",
"type": [
"boolean",
"null"
]
},
"kev_listed_total": {
"description": "Every CVE EchelonGraph holds as KEV-listed.",
"type": [
"number",
"null"
]
},
"limit": {
"type": [
"number",
"null"
]
},
"returned": {
"description": "Rows in this page.",
"type": [
"number",
"null"
]
},
"total": {
"description": "CVEs matching the filters.",
"type": [
"number",
"null"
]
}
},
"required": [
"catalog",
"total",
"returned",
"kev_listed_total",
"catalog_count",
"limit",
"has_more"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": {},
"properties": {
"catalog": {
"anyOf": [
{
"additionalProperties": {},
"properties": {
"catalog_count": {
"type": [
"number",
"null"
]
},
"catalog_version": {
"type": [
"string",
"null"
]
},
"date_released": {
"type": [
"string",
"null"
]
},
"feed_url": {
"type": [
"string",
"null"
]
},
"last_successful_fetch_at": {
"type": [
"string",
"null"
]
},
"source": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
{
"type": "null"
}
]
},
"count": {
"type": [
"number",
"null"
]
},
"filters": {
"anyOf": [
{
"additionalProperties": {},
"properties": {},
"type": "object"
},
{
"type": "null"
}
]
},
"generated_at": {
"type": [
"string",
"null"
]
},
"kev": {
"items": {
"additionalProperties": {},
"properties": {
"cve_id": {
"type": [
"string",
"null"
]
},
"cvss_v3_score": {
"type": [
"number",
"null"
]
},
"eg_kev_tier": {
"type": [
"number",
"null"
]
},
"epss_percentile": {
"type": [
"number",
"null"
]
},
"epss_score": {
"type": [
"number",
"null"
]
},
"kev_added_date": {
"type": [
"string",
"null"
]
},
"kev_due_date": {
"type": [
"string",
"null"
]
},
"kev_product": {
"type": [
"string",
"null"
]
},
"kev_ransomware": {
"type": [
"boolean",
"null"
]
},
"kev_vendor": {
"type": [
"string",
"null"
]
},
"kev_vuln_name": {
"type": [
"string",
"null"
]
},
"our_first_seen_kev": {
"description": "When EchelonGraph's poller first recorded the CVE entering the catalog; null where no such record exists.",
"type": [
"string",
"null"
]
},
"severity": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"kev_listed_total": {
"type": [
"number",
"null"
]
},
"limit": {
"type": [
"number",
"null"
]
},
"method": {
"type": [
"string",
"null"
]
},
"next_cursor": {
"type": [
"string",
"null"
]
},
"notes": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
]
},
"order": {
"type": [
"string",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"freshness": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"catalog_version": {
"type": [
"string",
"null"
]
},
"date_released": {
"type": [
"string",
"null"
]
},
"last_successful_fetch_at": {
"description": "When CISA last answered our poll of its feed: a 200 we applied, or a 304 Not Modified.",
"type": [
"string",
"null"
]
}
},
"required": [
"last_successful_fetch_at",
"catalog_version",
"date_released"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "The producing radar's last completed check (last_run_at), where the API serves one."
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"catalog": {
"const": "CISA KEV catalog",
"type": "string"
},
"catalog_count": {
"description": "CISA's own count, in the catalog last fetched.",
"type": [
"number",
"null"
]
},
"has_more": {
"description": "Whether next_cursor names a further page.",
"type": [
"boolean",
"null"
]
},
"kev_listed_total": {
"description": "Every CVE EchelonGraph holds as KEV-listed.",
"type": [
"number",
"null"
]
},
"limit": {
"type": [
"number",
"null"
]
},
"returned": {
"description": "Rows in this page.",
"type": [
"number",
"null"
]
},
"total": {
"description": "CVEs matching the filters.",
"type": [
"number",
"null"
]
}
},
"required": [
"catalog",
"total",
"returned",
"kev_listed_total",
"catalog_count",
"limit",
"has_more"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "Search/list CVEs from EchelonGraph's CVE feed (NVD + MITRE-CNA pre-NVD + CISA-KEV + EPSS + GitHub GHSA, each polled on a schedule). Filter by severity, minimum CVSS, free text, and sort. Returns cves, each with cve_id, severity, cvss_v3_score, echelongraph_score and score_assessed (whether EchelonGraph has scored it), epss_score and kev_listed where the record has them, and the list's total, total_counted (false: the matches were not counted, so total is not a count), total_is_lower_bound (true: at least total), search_relaxed (true: a phrase was relaxed to all of its words), limit and offset. echelongraph_score, echelongraph_severity and echelongraph_risk are EchelonGraph's score only when score_assessed is true. With score_assessed false the CVE is NOT YET SCORED, not scored 0: any of those three it carries (0, NONE, 0) is a placeholder, not a rating, and does not mean the CVE is harmless; the API may leave them out instead, score_confidence is NONE, and score_unassessed_reason says why (a rejected record, withdrawn by its numbering authority, is never scored, and the note says NOT SCORED). The note labels each such CVE NOT YET SCORED: report it that way, never as a score of 0. An answer with no score_assessed (an API older than that field) does not say whether the CVE was scored, the note says so, and a 0 there is not a rating either. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the feed serves no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends. coverage repeats total, total_counted, total_is_lower_bound, search_relaxed, limit and offset, and gives returned, the rows in this page.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"limit": {
"description": "page size (default 20, max 50)",
"maximum": 50,
"minimum": 1,
"type": "integer"
},
"min_cvss": {
"description": "minimum CVSS score",
"maximum": 10,
"minimum": 0,
"type": "number"
},
"search": {
"description": "free-text search (product, vendor, or keyword, e.g. 'tomcat')",
"type": "string"
},
"severity": {
"description": "filter to one severity",
"enum": [
"CRITICAL",
"HIGH",
"MEDIUM",
"LOW"
],
"type": "string"
},
"sort": {
"description": "sort order (default: published)",
"enum": [
"published",
"modified",
"nvd",
"echelongraph",
"epss"
],
"type": "string"
}
},
"type": "object"
},
"name": "search_cves",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"limit": {
"type": [
"number",
"null"
]
},
"offset": {
"type": [
"number",
"null"
]
},
"returned": {
"type": [
"number",
"null"
]
},
"search_relaxed": {
"type": [
"boolean",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
},
"total_counted": {
"type": [
"boolean",
"null"
]
},
"total_is_lower_bound": {
"type": [
"boolean",
"null"
]
}
},
"required": [
"total",
"total_counted",
"total_is_lower_bound",
"search_relaxed",
"returned",
"limit",
"offset"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": {},
"properties": {
"cves": {
"items": {
"additionalProperties": {},
"properties": {
"cpe_configurations": {
"anyOf": [
{
"items": {},
"type": "array"
},
{
"type": "null"
}
],
"description": "NVD's configurations array as NVD sent it: each configuration and node with its operator (AND, OR) and negate, and each cpeMatch with criteria, vulnerable, versionStartIncluding, versionStartExcluding, versionEndIncluding, versionEndExcluding and matchCriteriaId. A cpeMatch with vulnerable false inside an AND configuration is the platform the vulnerable product runs on, not an affected product. Absent: EchelonGraph holds no stored NVD configuration for the CVE, which is not a finding that no product is affected."
},
"cpe_match": {
"description": "The record's CPE match criteria as one flat list, every configuration's cpeMatch entries together: the AND/OR operator and negate of each configuration and node, versionStartExcluding and matchCriteriaId are not in it, so a CPE that is only a platform a product runs on reads as one more entry."
},
"cve_id": {
"type": [
"string",
"null"
]
},
"cvss_v3_score": {
"type": [
"number",
"null"
]
},
"cvss_v4_score": {
"type": [
"number",
"null"
]
},
"cvss_v4_severity": {
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"echelongraph_risk": {
"description": "EchelonGraph's 0-100 risk priority, fused from the score, exploitation and automatability: a rating only when score_assessed is true. With score_assessed false it is a placeholder.",
"type": [
"number",
"null"
]
},
"echelongraph_score": {
"description": "EchelonGraph's 0-10 score for the CVE: a score only when score_assessed is true. With score_assessed false it is a placeholder, not a rating.",
"type": [
"number",
"null"
]
},
"echelongraph_severity": {
"description": "The severity band of echelongraph_score: a rating only when score_assessed is true. With score_assessed false it is a placeholder (NONE).",
"type": [
"string",
"null"
]
},
"epss_percentile": {
"type": [
"number",
"null"
]
},
"epss_score": {
"type": [
"number",
"null"
]
},
"ghsa_id": {
"type": [
"string",
"null"
]
},
"kev_added_date": {
"type": [
"string",
"null"
]
},
"kev_listed": {
"type": [
"boolean",
"null"
]
},
"kev_ransomware": {
"type": [
"boolean",
"null"
]
},
"modified": {
"type": [
"string",
"null"
]
},
"published": {
"type": [
"string",
"null"
]
},
"references": {},
"score_assessed": {
"description": "Whether EchelonGraph has scored the CVE. true: echelongraph_score, echelongraph_severity and echelongraph_risk are its score. false: the CVE is NOT YET SCORED, not scored 0, and any of those three it carries is a placeholder, not a rating; the API may leave them out. Absent (an API older than the field): the answer does not say whether the CVE was scored.",
"type": [
"boolean",
"null"
]
},
"score_confidence": {
"type": [
"string",
"null"
]
},
"score_unassessed_reason": {
"description": "Why score_assessed is false: no_signal, no source has yet published severity data EchelonGraph can score; or rejected, the record was withdrawn by its numbering authority and is never scored. Absent when the CVE is scored.",
"type": [
"string",
"null"
]
},
"severity": {
"type": [
"string",
"null"
]
},
"updated_at": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"limit": {
"type": [
"number",
"null"
]
},
"offset": {
"type": [
"number",
"null"
]
},
"search_relaxed": {
"type": [
"boolean",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
},
"total_counted": {
"type": [
"boolean",
"null"
]
},
"total_is_lower_bound": {
"type": [
"boolean",
"null"
]
}
},
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"limit": {
"type": [
"number",
"null"
]
},
"offset": {
"type": [
"number",
"null"
]
},
"returned": {
"type": [
"number",
"null"
]
},
"search_relaxed": {
"type": [
"boolean",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
},
"total_counted": {
"type": [
"boolean",
"null"
]
},
"total_is_lower_bound": {
"type": [
"boolean",
"null"
]
}
},
"required": [
"total",
"total_counted",
"total_is_lower_bound",
"search_relaxed",
"returned",
"limit",
"offset"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "Search or list vendor-published advisories, newest first. query is matched case-insensitively as a substring of each advisory's title, description, vendor name, vendor_advisory_id, affected_products and cve_ids; filter by vendor (slug), by severity band, and by whether the advisory names any CVE ID. Advisories their vendor withdrew are left out. Returns advisories, each with vendor, vendor_advisory_id, title, severity, cvss_v3_score, cve_ids, summary and affected_products where present, and the answer's total, limit, offset and search_applied. Each advisory carries vendor_published_at (the vendor's date), our_first_seen_at (when EchelonGraph first recorded it) and withdrawn (true: the vendor rescinded it; the note names each such advisory). The query is sent in a request header, never in the URL. coverage repeats total, limit, offset and search_applied, and gives returned, the rows in this page. measured_at is null. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the answer carries no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"has_cve": {
"description": "true: only advisories naming a CVE; false: only those naming none",
"type": "boolean"
},
"limit": {
"description": "page size (default 20, max 50)",
"maximum": 50,
"minimum": 1,
"type": "integer"
},
"offset": {
"description": "rows to skip (default 0)",
"maximum": 10000,
"minimum": 0,
"type": "integer"
},
"query": {
"description": "free text, at most 100 bytes: a product, an advisory ID, a CVE ID or a keyword, e.g. 'exchange server'",
"type": "string"
},
"severity": {
"description": "one severity band",
"enum": [
"Critical",
"High",
"Medium",
"Low"
],
"type": "string"
},
"vendor": {
"description": "a vendor slug, e.g. microsoft, redhat, github",
"type": "string"
}
},
"type": "object"
},
"name": "search_vendor_advisories",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"limit": {
"type": [
"number",
"null"
]
},
"offset": {
"type": [
"number",
"null"
]
},
"returned": {
"type": [
"number",
"null"
]
},
"search_applied": {
"type": [
"boolean",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
}
},
"required": [
"total",
"returned",
"limit",
"offset",
"search_applied"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": {},
"properties": {
"advisories": {
"anyOf": [
{
"items": {
"additionalProperties": {},
"properties": {
"advisory_id": {
"type": [
"string",
"null"
]
},
"affected_products": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
]
},
"cve_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
]
},
"cvss_v3_score": {
"type": [
"number",
"null"
]
},
"our_first_seen_at": {
"description": "When EchelonGraph first recorded the advisory; not the vendor's date.",
"type": [
"string",
"null"
]
},
"severity": {
"type": [
"string",
"null"
]
},
"summary": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"vendor": {
"type": [
"string",
"null"
]
},
"vendor_advisory_id": {
"type": [
"string",
"null"
]
},
"vendor_display_name": {
"type": [
"string",
"null"
]
},
"vendor_published_at": {
"description": "The date the vendor gives for the advisory.",
"type": [
"string",
"null"
]
},
"withdrawn": {
"description": "true: the vendor withdrew (rescinded) this advisory; report it as withdrawn.",
"type": [
"boolean",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
]
},
"limit": {
"type": [
"number",
"null"
]
},
"offset": {
"type": [
"number",
"null"
]
},
"search_applied": {
"description": "Whether a free-text search filtered this answer.",
"type": [
"boolean",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"limit": {
"type": [
"number",
"null"
]
},
"offset": {
"type": [
"number",
"null"
]
},
"returned": {
"type": [
"number",
"null"
]
},
"search_applied": {
"type": [
"boolean",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
}
},
"required": [
"total",
"returned",
"limit",
"offset",
"search_applied"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
},
{
"description": "The vendor-published advisories that name one CVE, newest first, at most 20: for each, vendor, vendor_display_name, vendor_advisory_id, title, severity and cvss_v3_score where the vendor gives them. Covers the vendor feeds EchelonGraph polls, for example Microsoft MSRC, Red Hat, Cisco, Palo Alto Networks and GitHub GHSA; an empty answer means none of those names the CVE. Each advisory carries vendor_published_at (the vendor's date), our_first_seen_at (when EchelonGraph first recorded it) and withdrawn (true: the vendor rescinded it; the note names each such advisory). Pass a CVE ID like CVE-2024-21412. coverage gives returned, cap and at_cap (true: the answer is full, so there may be more). measured_at is null. Its structured result carries state (measured), measured_at, method, coverage, freshness (null: the answer carries no poll-completion time) and notes, with data equal to the API's JSON; the result's last text block repeats it without data (the first text block) and without the note's sentences (the text block before it), with which notes ends.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cve_id": {
"description": "a CVE ID, e.g. CVE-2024-21412",
"type": "string"
}
},
"required": [
"cve_id"
],
"type": "object"
},
"name": "vendor_advisories_for_cve",
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"at_cap": {
"description": "true: the answer is full, so the vendor feeds may hold more advisories for this CVE than it lists.",
"type": [
"boolean",
"null"
]
},
"cap": {
"description": "The most the API returns for one CVE, newest first.",
"type": "number"
},
"returned": {
"description": "The advisories in this answer.",
"type": [
"number",
"null"
]
}
},
"required": [
"returned",
"cap",
"at_cap"
],
"type": "object"
},
{
"type": "null"
}
],
"description": "What the answer covers; null where the answer says nothing about it."
},
"data": {
"additionalProperties": {},
"properties": {
"advisories": {
"anyOf": [
{
"items": {
"additionalProperties": {},
"properties": {
"advisory_id": {
"type": [
"string",
"null"
]
},
"affected_products": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
]
},
"cve_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
]
},
"cvss_v3_score": {
"type": [
"number",
"null"
]
},
"our_first_seen_at": {
"description": "When EchelonGraph first recorded the advisory; not the vendor's date.",
"type": [
"string",
"null"
]
},
"severity": {
"type": [
"string",
"null"
]
},
"summary": {
"type": [
"string",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"vendor": {
"type": [
"string",
"null"
]
},
"vendor_advisory_id": {
"type": [
"string",
"null"
]
},
"vendor_display_name": {
"type": [
"string",
"null"
]
},
"vendor_published_at": {
"description": "The date the vendor gives for the advisory.",
"type": [
"string",
"null"
]
},
"withdrawn": {
"description": "true: the vendor withdrew (rescinded) this advisory; report it as withdrawn.",
"type": [
"boolean",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
]
},
"cve_id": {
"type": [
"string",
"null"
]
},
"total": {
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"freshness": {
"description": "The producing radar's last completed check (last_run_at), where the API serves one.",
"type": "null"
},
"measured_at": {
"anyOf": [
{
"description": "An RFC 3339 instant.",
"type": "string"
},
{
"type": "null"
}
],
"description": "When the underlying observation was made, as the API states it; null when the answer does not say or holds no observation."
},
"method": {
"description": "How the numbers were produced.",
"type": "string"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "measured: a measurement of what was asked; an exposure count is measured only with measured_at and method. not_assessed: the answer holds no dated measurement of what was asked, so no count in it is presented as one; it can still relay a count, as what the source holds on record, undated, and its notes (and exposure_state, where the result carries it) say what each count is.",
"enum": [
"measured",
"not_assessed"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"data"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"coverage": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"at_cap": {
"description": "true: the answer is full, so the vendor feeds may hold more advisories for this CVE than it lists.",
"type": [
"boolean",
"null"
]
},
"cap": {
"description": "The most the API returns for one CVE, newest first.",
"type": "number"
},
"returned": {
"description": "The advisories in this answer.",
"type": [
"number",
"null"
]
}
},
"required": [
"returned",
"cap",
"at_cap"
],
"type": "object"
},
{
"type": "null"
}
]
},
"error": {
"additionalProperties": false,
"properties": {
"kind": {
"description": "What failed: the request (network, timeout), the answer (http, not_json, not_object, unexpected_shape), the input, or this server.",
"enum": [
"network",
"timeout",
"http",
"not_json",
"not_object",
"invalid_input",
"internal",
"unexpected_shape",
"radars"
],
"type": "string"
},
"message": {
"description": "The cause: the API's own message, or what went wrong.",
"type": "string"
},
"path": {
"description": "The API path requested, when a request was made.",
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
],
"description": "The HTTP status, when the API answered one."
}
},
"required": [
"kind",
"path",
"status",
"message"
],
"type": "object"
},
"freshness": {
"type": "null"
},
"measured_at": {
"type": "null"
},
"method": {
"type": "null"
},
"notes": {
"description": "Caveats, one sentence each.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "failed: the lookup did not complete. invalid_input: the input was refused, so nothing was looked up. Neither is a finding.",
"enum": [
"failed",
"invalid_input"
],
"type": "string"
}
},
"required": [
"state",
"measured_at",
"method",
"coverage",
"freshness",
"notes",
"error"
],
"type": "object"
}
],
"type": "object"
}
}
]
}Verify it yourself
curl -s https://api.teppi.xyz/v1/evidence/sha256:5884ca174de2dc4421a4d8db70a9b479e36edce1e7c6a7d898bd9735ac04700e | sha256sum