Skip to content
Reference

Vultron ActivityStreams Objects

This page is not normative

This page is not considered a core part of the Vultron Protocol as proposed in the main documentation. Although within the page we might provide guidance in terms of SHOULD, MUST, etc., the content here is not normative.

Vultron ActivityStreams (Vultron AS) is an extension of the ActivityStreams vocabulary to describe the mapping of Vultron to ActivityStreams. This page shows each Vultron object as it appears on the wire. The normative definition of the object types is §5.2 Object Types of the Vultron Protocol Specification; the activities that carry them are cataloged in Message Types. For why the extension is as small as it is, and when a new object type is minted rather than reusing a native one, see Activity Vocabulary Design.

ActivityStreams native objects

The ActivityStreams Vocabulary defines a number of native object types that can be used to represent objects in the ActivityPub protocol. These fall into the following categories:

Actors

Actor vs CaseParticipant

The CaseParticipant object type (defined below) represents the participants in a VulnerabilityCase. The as:Actor types represent persistent identities within a larger ActivityPub network, while a CaseParticipant is a contextual identity that associates an actor to a specific VulnerabilityCase object. This distinction allows the Vultron protocol to represent a single actor participating in multiple cases, with discrete roles and statuses within the context of each case.

The standard ActivityStreams actor types can be used in Vultron. These include:

  • as:Person
  • as:Organization
  • as:Group
  • as:Service
  • as:Application

Other (non-Activity) Object Types

ActivityStreams also includes a number of native object types, including:

  • as:Article
  • as:Collection, including as:OrderedCollection
  • as:Document, including as:Audio, as:Image, and as:Video
  • as:Event
  • as:Note
  • as:Page
  • as:Place
  • as:Profile
  • as:Relationship
  • as:Tombstone

as:Note is used to represent comments on a VulnerabilityCase. The EmbargoEvent object is a specialization of the as:Event object. Systems implementing the Vultron protocol may use other ActivityStreams object types as needed; no special semantics are defined for those objects in the context of the Vultron protocol.

Vultron-specific objects

See also

These objects are also described in the Case Model section. This section describes how these objects are represented as ActivityStreams objects.

The following objects are defined for use in the Vultron AS vocabulary:

A case contains its participants, its report, its status records, its embargo events, and its ledger entries; a CaseProposal precedes the case and asks for one to be created.

VulnerabilityReport

A VulnerabilityReport object is used to represent a vulnerability report as an ActivityStreams object. This protocol does not define a full vulnerability report data object. Instead, it defines a minimal set of properties necessary to support the protocol.

The example below shows a VulnerabilityReport object containing a simple text description of a vulnerability in the content property. In a real implementation, the content property may contain any vulnerability report format that can be embedded as part of the JSON object.

Examples of what might go into the content property of a VulnerabilityReport object include:

  • Community-developed Structured formats like CSAF or CVE JSON
  • Quasi-structured text formats based on templates like the OWASP Vulnerability Template
  • Proprietary formats used by vendors, coordinators, or finders, such as might be found behind a web form like CERT/CC's Vulnerability Reporting Form
  • A plain text description of the vulnerability, for example a markdown-formatted text description with section headings and links to external resources

The format of the content property is deliberately open-ended to allow for flexibility in the types of vulnerability reports that can be represented. The content property SHOULD represent a widely-used structured format whenever possible, since this allows for more automation in the processing of vulnerability reports.

Binary attachments (PDF documents, images, audio files, video files) are supported; in those cases, the content property MAY contain a link to the binary file or an embedded encoding. Binary attachments SHOULD be avoided whenever possible since they are more difficult to process automatically.

{
  "id": "https://demo.vultron.local/VulnerabilityReport/e28f4965-7838-4644-b4a8-10604c7ee92f",
  "type": "VulnerabilityReport",
  "name": "FDR-8675309",
  "content": "I found a vulnerability!",
  "attributedTo": "https://vultron.example/users/finndervul",
  "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
}

Articles and Documents

A VulnerabilityReport or advisory draft could also be an as:Article or as:Document, but those types are not used explicitly by the protocol.

VulnerabilityCase

A VulnerabilityCase object is used to represent a vulnerability case as an ActivityStreams object. As with VulnerabilityReport, this protocol does not define a full vulnerability case data object. Instead, it defines a minimal set of properties necessary to support the protocol. The VulnerabilityCase object is consistent with the Case Model defined elsewhere.

ActivityStreams Objects are for Interoperability

These objects are intended to promote interoperability between systems that communicate using ActivityPub. They are not intended to be used as a data model for a single system. For example, one vendor might use Github issues to track vulnerability cases, while another might use Jira. Both vendors could use the same VulnerabilityCase object to represent their cases in ActivityPub, but they would not necessarily use the same data model internally.

{
  "id": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
  "type": "VulnerabilityCase",
  "name": "VendorCo Case #70930046",
  "attributedTo": "https://vultron.example/organizations/vendorco",
  "caseParticipants": [
    {
      "id": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0/participants/finndervul",
      "type": "CaseParticipant",
      "name": "Finn der Vul",
      "context": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
      "published": "2026-10-23T20:17:15+00:00",
      "updated": "2026-10-23T20:17:15+00:00",
      "attributedTo": "https://vultron.example/users/finndervul",
      "caseRoles": [
        "reporter"
      ],
      "participantStatuses": [
        {
          "id": "urn:uuid:a0dd7400-7be7-4279-a1d0-d38c04211466",
          "type": "ParticipantStatus",
          "name": "START",
          "context": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
          "published": "2026-10-23T20:17:15+00:00",
          "updated": "2026-10-23T20:17:15+00:00",
          "attributedTo": "https://vultron.example/users/finndervul",
          "rmState": "START",
          "caseEngagement": true,
          "cvdRole": [
            "REPORTER"
          ],
          "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
        }
      ],
      "embargoConsents": [],
      "joined": true,
      "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
    },
    {
      "id": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0/participants/vendorco",
      "type": "CaseParticipant",
      "name": "VendorCo",
      "context": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
      "published": "2026-10-23T20:17:15+00:00",
      "updated": "2026-10-23T20:17:15+00:00",
      "attributedTo": "https://vultron.example/organizations/vendorco",
      "caseRoles": [
        "vendor"
      ],
      "participantStatuses": [
        {
          "id": "urn:uuid:12b14470-277d-425f-97c2-bc86fc1cc1df",
          "type": "ParticipantStatus",
          "name": "RECEIVED Vf",
          "context": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
          "published": "2026-10-23T20:17:15+00:00",
          "updated": "2026-10-23T20:17:15+00:00",
          "attributedTo": "https://vultron.example/organizations/vendorco",
          "rmState": "RECEIVED",
          "vfState": "Vf",
          "caseEngagement": true,
          "cvdRole": [
            "OBSERVER"
          ],
          "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
        }
      ],
      "embargoConsents": [],
      "joined": true,
      "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
    }
  ],
  "actorParticipantIndex": {
    "https://vultron.example/users/finndervul": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0/participants/finndervul",
    "https://vultron.example/organizations/vendorco": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0/participants/vendorco"
  },
  "vulnerabilityReports": [
    {
      "id": "https://demo.vultron.local/VulnerabilityReport/e28f4965-7838-4644-b4a8-10604c7ee92f",
      "type": "VulnerabilityReport",
      "name": "FDR-8675309",
      "published": "2026-10-23T20:17:06+00:00",
      "updated": "2026-10-23T20:17:06+00:00",
      "content": "I found a vulnerability!",
      "attributedTo": "https://vultron.example/users/finndervul",
      "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
    }
  ],
  "caseStatuses": [
    {
      "id": "urn:uuid:170985a7-8e97-4cec-9e5c-7a6a9848d303",
      "type": "CaseStatus",
      "name": "NONE pxa",
      "context": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
      "published": "2026-10-23T20:17:15+00:00",
      "updated": "2026-10-23T20:17:15+00:00",
      "attributedTo": "https://vultron.example/organizations/vendorco",
      "emState": "NONE",
      "pxaState": "pxa",
      "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
    }
  ],
  "notes": [],
  "embargoRegister": [],
  "pendingEmbargoProposalIndex": {},
  "caseActivity": [],
  "genesisHash": "b34c59e8d277a13cb81300aa87d7e32c34e04515e015e845a1768b301cd0775f",
  "ledgerPosition": {
    "logIndex": -1,
    "entryHash": "b34c59e8d277a13cb81300aa87d7e32c34e04515e015e845a1768b301cd0775f"
  },
  "parentCases": [],
  "childCases": [],
  "siblingCases": [],
  "activeParticipants": [
    "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0/participants/finndervul",
    "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0/participants/vendorco"
  ],
  "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
}

CaseStatus

A CaseStatus object is used to represent the participant-agnostic status of a VulnerabilityCase object. It is canonical: it carries what the case asserts, and only the CASE_MANAGER writes it (§5.4.1 Single-Writer Authority). The semantics of the CaseStatus object are described in the Case Model section. The distinction between participant-agnostic and participant-specific status is described in the Global vs Local section.

{
  "id": "https://vultron.example/cases/1/status/1",
  "type": "CaseStatus",
  "name": "NONE pxa",
  "context": "https://vultron.example/cases/1",
  "emState": "NONE",
  "pxaState": "pxa",
  "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
}

CaseParticipant

As noted above, the CaseParticipant object is a wrapper around an as:Actor object that associates the actor with a specific VulnerabilityCase object. The CaseParticipant object is intended to be consistent with the CaseParticipant defined as part of the Case Model. The CaseParticipant object also includes a participantStatus property that describes the participant's status in the case as it progresses.

{
  "id": "https://vultron.example/cases/1/participants/vendor",
  "type": "CaseParticipant",
  "name": "Vendor",
  "context": "https://vultron.example/cases/1",
  "attributedTo": "https://vultron.example/organizations/vendor",
  "caseRoles": [
    "vendor"
  ],
  "participantStatuses": [
    {
      "id": "https://vultron.example/cases/1/participants/vendor/status/1",
      "type": "ParticipantStatus",
      "name": "RECEIVED Vf NONE pxa",
      "context": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
      "published": "2026-06-01T19:12:00+00:00",
      "updated": "2026-06-01T19:12:00+00:00",
      "attributedTo": "https://vultron.example/organizations/vendor",
      "rmState": "RECEIVED",
      "vfState": "Vf",
      "caseEngagement": true,
      "cvdRole": [
        "OBSERVER"
      ],
      "caseStatus": {
        "id": "https://vultron.example/cases/1/status/1",
        "type": "CaseStatus",
        "name": "NONE pxa",
        "context": "https://vultron.example/cases/1",
        "published": "2026-06-01T19:12:00+00:00",
        "updated": "2026-06-01T19:12:00+00:00",
        "emState": "NONE",
        "pxaState": "pxa",
        "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
      },
      "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
    }
  ],
  "embargoConsents": [],
  "joined": true,
  "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
}

ParticipantStatus

A ParticipantStatus object is used to represent the participant-specific status of a CaseParticipant within the context of a VulnerabilityCase object. As noted above, see the Global vs Local section for more information about the distinction between participant-agnostic and participant-specific status.

{
  "id": "https://vultron.example/cases/1/participants/vendor/status/1",
  "type": "ParticipantStatus",
  "name": "RECEIVED Vf NONE pxa",
  "context": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
  "attributedTo": "https://vultron.example/organizations/vendor",
  "rmState": "RECEIVED",
  "vfState": "Vf",
  "caseEngagement": true,
  "cvdRole": [
    "OBSERVER"
  ],
  "caseStatus": {
    "id": "https://vultron.example/cases/1/status/1",
    "type": "CaseStatus",
    "name": "NONE pxa",
    "context": "https://vultron.example/cases/1",
    "published": "2026-06-01T19:12:00+00:00",
    "updated": "2026-06-01T19:12:00+00:00",
    "emState": "NONE",
    "pxaState": "pxa",
    "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
  },
  "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
}

Why is there a CaseStatus inside the ParticipantStatus?

A ParticipantStatus is a claim, and a CaseStatus is canonical. The CaseStatus inside a ParticipantStatus lets a participant state what it believes the case as a whole has reached, without that belief becoming the case's state. For example, a vendor might observe that an exploit has been released while the case still records the vulnerability as unexploited. The vendor includes a CaseStatus in its ParticipantStatus showing Exploit Public. The CASE_MANAGER then decides whether to adopt the claim, by default with the Case Owner's authorization, and if it does it writes the canonical CaseStatus on the VulnerabilityCase with pxaState including X (§10.3 Status Adoption: The Two-Seam Model, §12.4.4 Case Owner Authority). No other participant writes the canonical CaseStatus (§5.4.1 Single-Writer Authority).

EmbargoEvent

An EmbargoEvent object is used to represent the end date and time of an embargo event as an ActivityStreams object. It is a specialization of the as:Event object.

{
  "id": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0/embargo_events/2026-08-30T00:00:00+00:00",
  "type": "EmbargoEvent",
  "name": "Embargo for VendorCo Case #70930046",
  "context": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
  "startTime": "2026-06-01T19:12:00+00:00",
  "endTime": "2026-08-30T00:00:00+00:00",
  "content": "We propose to embargo VendorCo Case #70930046 for 90 days.",
  "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
}

CaseParticipantRole

A CaseParticipantRole object carries a single CVD role being offered to an actor in the context of a case. It is a distinct type so that offering a role (Offer(CaseParticipantRole)) is structurally different from offering ownership of the case (Offer(VulnerabilityCase)); see Case Management Messages. The example is the object carried by such an offer.

{
  "@context": "https://certcc.github.io/Vultron/ns/context.jsonld",
  "type": "CaseParticipantRole",
  "id": "urn:uuid:cc725e25-71d8-41cf-8c4d-a0508caded4f",
  "role": "coordinator"
}

CaseLedgerEntry

A CaseLedgerEntry object is one entry in the canonical case ledger. The CASE_MANAGER writes an entry for every case-scoped message and fans it out to participants with Announce(CaseLedgerEntry); each entry carries the hash of the previous one, which is how participants detect a gap. See Ledger Replication for the activities that carry it. The example is the object carried by such an announcement.

{
  "id": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0/log/0",
  "type": "CaseLedgerEntry",
  "caseId": "urn:uuid:d483d06d-400e-47fd-9b8a-9a2643e3a4b0",
  "logIndex": 0,
  "logObjectId": "https://vultron.example/activities/00000000-0000-0000-0000-000000000001",
  "semanticType": "create_case",
  "payloadSnapshot": {},
  "prevLogHash": "0000000000000000000000000000000000000000000000000000000000000000",
  "entryHash": "6a4f6f8e7016eb9b177a78414c7c985f52eeccfe02484be2aa56e76f9363eb7a",
  "receivedAt": "2024-01-01T12:00:00Z",
  "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
}

CaseProposal

A CaseProposal object asks another actor to create and manage a case around a report. It is used when the actor holding the report does not intend to manage the case itself; the actor that accepts the proposal becomes the case's creator. The report is carried inline, and target names the prospective case-actor service. See Case Proposal for the three-message flow.

{
  "@context": "https://certcc.github.io/Vultron/ns/context.jsonld",
  "type": "CaseProposal",
  "id": "urn:uuid:df859095-adfd-4c69-bf1b-80dd162c1639",
  "summary": "Request case initialization for a new vulnerability.",
  "attributedTo": "https://vultron.example/organizations/vendorco",
  "object": {
    "id": "https://demo.vultron.local/VulnerabilityReport/e28f4965-7838-4644-b4a8-10604c7ee92f",
    "type": "VulnerabilityReport",
    "name": "FDR-8675309",
    "published": "2026-10-23T20:17:06+00:00",
    "updated": "2026-10-23T20:17:06+00:00",
    "content": "I found a vulnerability!",
    "attributedTo": "https://vultron.example/users/finndervul",
    "@context": "https://certcc.github.io/Vultron/ns/context.jsonld"
  },
  "target": "https://example.org/case-actors/alpha",
  "proposerCaseRoles": [
    "vendor"
  ]
}