{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/honeylabs-net/json-schema/honeylabs-net-cve-detail-schema.json",
  "title": "CveDetail",
  "description": "Counts cover both sensor types: first contact (requests matching the CVE's detection signatures) and the requests the interactive sensors answered that count as a probe for the CVE (the sensor's rule for that CVE was the only one the request matched, on a path first contact's exclusions accept, or the request or its session carried the exploit). A request that matched several CVE rules counts for none. UDP is left out on both sides.",
  "x-generated": "2026-11-11",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/honeylabs-net-openapi.json#/components/schemas/CveDetail",
  "type": "object",
  "properties": {
    "cve_id": {
      "type": "string"
    },
    "title": {
      "type": "string",
      "description": "The detection signature's title, else the KEV catalogue's vulnerabilityName, else a title HoneyLabs writes for an id the interactive sensors record that neither names. Empty when none applies."
    },
    "severity": {
      "type": "string"
    },
    "actively_exploited": {
      "type": "boolean",
      "description": "On the CISA Known Exploited Vulnerabilities catalogue, or flagged as listed by the CVE's detection signatures. The catalogue is the first source and covers CVEs without a signature."
    },
    "events": {
      "type": "integer",
      "description": "first_contact_events plus interactive_requests."
    },
    "unique_ips": {
      "type": "integer",
      "description": "Distinct addresses over both sensor types, each once."
    },
    "first_contact_events": {
      "type": "integer"
    },
    "first_contact_ips": {
      "type": "integer"
    },
    "interactive_requests": {
      "type": "integer"
    },
    "interactive_sources": {
      "type": "integer"
    },
    "patterns": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "actors": {
      "type": "array",
      "description": "Top sources over both sensor types, most events first.",
      "items": {
        "type": "object",
        "properties": {
          "ip": {
            "type": "string"
          },
          "events": {
            "type": "integer"
          },
          "first_contact_events": {
            "type": "integer"
          },
          "interactive_requests": {
            "type": "integer",
            "description": "Requests the interactive sensors answered from this address; 0 when none."
          },
          "country_code": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "org": {
            "type": "string"
          },
          "rdns": {
            "type": "string"
          },
          "scanner_tag": {
            "type": [
              "object",
              "null"
            ],
            "description": "The address's classification chip, hosting providers included; `scanner` says whether it is a recognised scanner."
          },
          "scanner": {
            "type": [
              "object",
              "null"
            ],
            "description": "Set when the platform recognises the address as a scanner, by the signals the address report's \"Recognized scanner\" verdict reads: a research, commercial or vendor rule matching its reverse DNS or network name, or its address inside a known scanner range. null for every other address, hosting providers included.",
            "properties": {
              "name": {
                "type": "string",
                "description": "The scanner's name in words, such as Censys. Empty when the range list names only a kind (university research scanners)."
              },
              "category": {
                "type": "string",
                "enum": [
                  "research",
                  "commercial",
                  "vendor",
                  ""
                ],
                "description": "The kind of scanner; empty when no rule or list entry says."
              }
            }
          }
        }
      }
    },
    "window_notice": {
      "$ref": "#/$defs/WindowNotice"
    },
    "interaction": {
      "$ref": "#/$defs/CveInteraction"
    },
    "known": {
      "type": "boolean",
      "description": "probe_tags holds the CVE, or the interactive sensors saw it probed in the last 90 days. A known CVE with no activity in the window answers 200 with zeros."
    },
    "body_patterns": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "top_asns": {
      "type": "array",
      "description": "At most 10, both sensor types.",
      "items": {
        "type": "object",
        "properties": {
          "asn": {
            "type": "integer"
          },
          "org": {
            "type": "string"
          },
          "events": {
            "type": "integer"
          },
          "ips": {
            "type": "integer"
          },
          "interactive_requests": {
            "type": "integer"
          }
        }
      }
    },
    "top_countries": {
      "type": "array",
      "description": "At most 10, both sensor types.",
      "items": {
        "type": "object",
        "properties": {
          "country_code": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "events": {
            "type": "integer"
          },
          "ips": {
            "type": "integer"
          },
          "interactive_requests": {
            "type": "integer"
          }
        }
      }
    },
    "fingerprints": {
      "type": "object",
      "properties": {
        "ja4": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "akin": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    },
    "sample_paths": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "First-contact request paths, at most 10."
    },
    "timeline": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "day": {
            "type": "string",
            "description": "YYYY-MM-DD, UTC"
          },
          "events": {
            "type": "integer"
          },
          "ips": {
            "type": "integer",
            "description": "Distinct addresses that day over both sensor types."
          },
          "first_contact_events": {
            "type": "integer"
          },
          "interactive_requests": {
            "type": "integer"
          }
        }
      },
      "description": "One row per day either sensor type saw."
    },
    "interactive": {
      "$ref": "#/$defs/CveInteractive"
    },
    "window_hours": {
      "type": "integer"
    },
    "kev_date_added": {
      "type": [
        "string",
        "null"
      ],
      "description": "The date CISA added the CVE to the KEV catalogue (YYYY-MM-DD, its dateAdded). null when the catalogue does not list it."
    },
    "kev": {
      "type": [
        "object",
        "null"
      ],
      "description": "The CVE's entry in the CISA KEV catalogue; null when the catalogue does not list it.",
      "properties": {
        "date_added": {
          "type": "string",
          "description": "YYYY-MM-DD"
        },
        "vulnerability_name": {
          "type": "string"
        },
        "vendor_project": {
          "type": "string"
        },
        "product": {
          "type": "string"
        },
        "known_ransomware_campaign_use": {
          "type": "string",
          "description": "CISA's value: Known or Unknown."
        }
      }
    }
  },
  "$defs": {
    "CveInteraction": {
      "type": [
        "object",
        "null"
      ],
      "description": "What the interactive sensors recorded for this CVE: sessions in which a client went on to send the exploit after the sensor answered as the vulnerable service. null when there were none in the window. Hosts are defanged; render them as text, never as links.",
      "properties": {
        "window_days": {
          "type": "integer"
        },
        "sessions": {
          "type": "integer"
        },
        "sources": {
          "type": "integer",
          "description": "Distinct source addresses behind the sessions."
        },
        "top_asns": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "asn": {
                "type": "integer"
              },
              "org": {
                "type": "string"
              },
              "sessions": {
                "type": "integer"
              }
            }
          }
        },
        "followed_by": {
          "type": "object",
          "description": "What the client did after sending the exploit.",
          "properties": {
            "downloads": {
              "type": "integer"
            },
            "commands": {
              "type": "integer"
            },
            "uploads": {
              "type": "integer",
              "description": "Sessions that handed the sensor a file other than the exploit's own body."
            }
          }
        },
        "download_hosts": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "host": {
                "type": "string",
                "description": "Defanged, e.g. 203[.]0[.]113[.]9."
              },
              "sessions": {
                "type": "integer"
              }
            }
          }
        },
        "recent": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "ts": {
                "type": "string"
              },
              "country_code": {
                "type": "string"
              },
              "asn_org": {
                "type": "string"
              },
              "protocol": {
                "type": "string"
              },
              "dest_port": {
                "type": "integer"
              },
              "did": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "What the session did in words: logged in, tried logins, ran commands, named a download, uploaded a file, sent an exploit. The sensor's own labels are never published."
              }
            }
          }
        }
      }
    },
    "CveInteractive": {
      "type": [
        "object",
        "null"
      ],
      "description": "What the interactive sensors recorded of the probes for this CVE in the window. null when they answered none. Paths, user agents and payload excerpts are attacker text with every URL and address defanged; render them as text, never as links.",
      "properties": {
        "requests": {
          "type": "integer",
          "description": "Counted requests (as interactive_requests)."
        },
        "sources": {
          "type": "integer",
          "description": "Distinct source addresses behind them."
        },
        "payload_sources": {
          "type": "integer",
          "description": "How many of those sources sent the exploit payload."
        },
        "payload_sessions": {
          "type": "integer",
          "description": "Sessions whose payload proved the CVE, any transport."
        },
        "first_seen": {
          "type": [
            "string",
            "null"
          ]
        },
        "last_seen": {
          "type": [
            "string",
            "null"
          ]
        },
        "top_sources": {
          "type": "array",
          "description": "At most 25, most requests first.",
          "items": {
            "type": "object",
            "properties": {
              "ip": {
                "type": "string"
              },
              "requests": {
                "type": "integer"
              },
              "payload": {
                "type": "boolean",
                "description": "Sent the exploit payload."
              },
              "country_code": {
                "type": "string"
              },
              "country": {
                "type": "string"
              },
              "asn": {
                "type": "integer"
              },
              "org": {
                "type": "string"
              },
              "first_seen": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "last_seen": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "scanner": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "Set when the platform recognises the address as a scanner, by the signals the address report's \"Recognized scanner\" verdict reads: a research, commercial or vendor rule matching its reverse DNS or network name, or its address inside a known scanner range. null for every other address, hosting providers included.",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "The scanner's name in words, such as Censys. Empty when the range list names only a kind (university research scanners)."
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "research",
                      "commercial",
                      "vendor",
                      ""
                    ],
                    "description": "The kind of scanner; empty when no rule or list entry says."
                  }
                }
              }
            }
          }
        },
        "paths": {
          "type": "array",
          "description": "Requests by method and path, at most 25.",
          "items": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string"
              },
              "path": {
                "type": "string"
              },
              "requests": {
                "type": "integer"
              },
              "sources": {
                "type": "integer"
              }
            }
          }
        },
        "user_agents": {
          "type": "array",
          "description": "At most 10.",
          "items": {
            "type": "object",
            "properties": {
              "user_agent": {
                "type": "string"
              },
              "requests": {
                "type": "integer"
              }
            }
          }
        },
        "payloads": {
          "type": "array",
          "description": "Request bodies that carried the exploit, one per distinct body, with one of the paths it was sent to and how many.",
          "items": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string"
              },
              "path": {
                "type": "string"
              },
              "paths": {
                "type": "integer"
              },
              "excerpt": {
                "type": "string",
                "description": "The body as sent, the first 4,000 characters, URLs and addresses defanged."
              },
              "requests": {
                "type": "integer"
              },
              "decoded": {
                "type": "string",
                "description": "An encoded stage in the body (PHP base64_decode('...'), echo ... | base64 -d) decoded to text, URLs and addresses defanged; empty when there is none."
              }
            }
          }
        },
        "bodies": {
          "type": "array",
          "description": "Other bodies of counted requests, same shape as payloads.",
          "items": {
            "type": "object"
          }
        },
        "after": {
          "type": "array",
          "description": "What these sources did on the interactive sensors from their first probe on (TCP sessions, any service), for sources that did more than probe. At most 25.",
          "items": {
            "type": "object",
            "properties": {
              "ip": {
                "type": "string"
              },
              "sessions": {
                "type": "integer"
              },
              "logged_in": {
                "type": "integer",
                "description": "Sessions that logged in."
              },
              "commands": {
                "type": "integer",
                "description": "Sessions that ran commands."
              },
              "downloads": {
                "type": "integer",
                "description": "Sessions that named a download."
              },
              "uploads": {
                "type": "integer",
                "description": "Sessions that uploaded a file."
              },
              "last_seen": {
                "type": "string"
              },
              "did": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The same in words: logged in, ran commands, named a download, uploaded a file."
              }
            }
          }
        },
        "scanner_sources": {
          "type": "integer",
          "description": "How many of `sources` the platform recognises as scanners, counted over every source, not only the listed ones."
        },
        "payload_scanner_sources": {
          "type": "integer",
          "description": "How many of the recognised scanners sent the exploit payload."
        },
        "scanner_category": {
          "type": "string",
          "enum": [
            "research",
            "commercial",
            "vendor",
            ""
          ],
          "description": "The kind every recognised scanner among the sources shares; empty when they differ, none is known, or there are none."
        }
      }
    },
    "WindowNotice": {
      "type": "object",
      "description": "Present when the requested window exceeded the plan and the response was shortened.",
      "properties": {
        "requested_days": {
          "type": "integer"
        },
        "returned_days": {
          "type": "integer"
        },
        "reason": {
          "type": "string"
        },
        "upgrade": {
          "type": "string",
          "format": "uri"
        }
      }
    }
  }
}