Skip to content
Reference

Transport and Security

This page is normative

This page is considered a core part of the Vultron Protocol. This is a normative section of the documentation.

The whole specification on one page

The specification is also published as a single page that holds every section and annex in order, for printing or for searching the whole text at once.

This page holds section 14.7 of the Vultron Protocol Specification, part of its Requirements Catalog. Each row is one requirement, and the rest of the documentation links a requirement to its row here.

14.7 Transport and Security

The requirements on transport and security: the Hypertext Transfer Protocol (HTTP) transport, the inbox endpoint, the outbox, message signing, and encryption.

HTTP Protocol Requirements

HTTP protocol requirements for the Vultron API, covering status codes, headers, and content negotiation.

Content-Type Validation

ID Priority Requirement Related
HTTP-01-001 MUST Inbox endpoint MUST accept application/activity+json Content-Type

ActivityPub only says a server SHOULD treat application/activity+json as equivalent to the JSON-LD media type it names for delivery (HTTP-01-002). Vultron makes that SHOULD a MUST, so the rule is Vultron's own, not inherited.

Response Headers

ID Priority Requirement Related
HTTP-04-001 MUST Endpoints returning ActivityStreams objects MUST use Content-Type: application/activity+json.

ActivityPub allows an ActivityStreams document to be served as either application/activity+json or application/ld+json; profile="https://www.w3.org/ns/activitystreams". Requiring the first picks one form among those the standard allows, so the rule is Vultron's own (MS-12-009), as the inbox's media-type rule is (HTTP-01-001). Plain application/json is ambiguous for federation clients that discover capabilities via Content-Type.

Inbox Endpoint

The inbox endpoint is the primary entry point for actor-to-actor communication in Vultron. It receives ActivityStreams activities via HTTP POST, validates them, and queues them for asynchronous processing.

Activity Validation

ID Priority Requirement Related
IE-04-001 MUST The endpoint MUST validate each activity's structure against the message form its type requires

A receiver acts on an activity according to its type. A malformed activity can be read as the wrong message, or its processing can fail part of the way through. If the receiver checks the form when the activity arrives, it refuses the activity once, with a clear reason, and later steps work on an activity whose form is known (ADR-0032).

Activity Addressing

ID Priority Requirement Related
IE-11-001 MUST The inbox endpoint MUST refuse any Activity whose addressing fields (to, cc, bto, bcc) are all non-empty and none of them names the receiving actor.

Per-actor DataLayer isolation (ADR-0073) makes each actor's store the authoritative answer to "whose replica is this?". That invariant is only trustworthy if the store's owner was the intended recipient of every Activity it processed. Which HTTP response carries the refusal is this codebase's choice, not a protocol rule: it answers HTTP 400 in place of the 202 (IE-07-002, project), so the sender learns of the refusal from the answer to its own delivery.
Depends on: IE-07-002 — the HTTP status that carries the refusal is this codebase's choice
IE-11-004 MUST NOT The inbox endpoint MUST NOT write anything to the receiving actor's store for an Activity that IE-11-001 refuses.

A record of a misaddressed Activity would make the store hold an activity that its owner was not meant to receive. The store would then no longer answer "whose replica is this?" with certainty (ADR-0073).
Extends: IE-11-001
IE-11-002 MUST The inbox endpoint MUST accept Activities whose addressing fields (to, cc, bto, bcc) are all absent or unresolvable (Liberal Accept). An address is unresolvable if it cannot be confirmed to refer to a specific individual actor — for example, a collection URI such as {case_id}/participants.

Requiring explicit addressing would break flows where Activities are sent without formal addressing (e.g., internal relay, legacy senders). The narrowest thing that can be refused is provable exclusion; uncertainty defaults to acceptance. Fan-out deliveries using collection URIs (e.g. {case_id}/participants) cannot be resolved to individual actors at inbox processing time and must therefore be accepted.
IE-11-003 MUST The inbox endpoint MUST consider all four addressing fields — to, cc, bto, bcc — when determining whether the receiving actor is named as a recipient. A match on any one field is sufficient.

ActivityStreams has several audience properties, and Vultron decides which of them count as addressing, so the rule is Vultron's own. Vultron defines no use for audience on any object or activity, so an actor named only there is not addressed. Vultron sets only to (OX-08), but another implementation can name this actor only in cc, bto or bcc. If the inbox checks only to, it refuses that activity wrongly. HP-10 decides what an address only in cc means.

Outbox

Requirements for actor outboxes, which hold response activities generated by handlers. Covers outbox structure, population, delivery, local and federated dispatch, idempotency, outbound reference dehydration, and outbox addressing rules.

Undelivered-Activity Correlation

Requirements linking a permanently undelivered activity back to the canonical case ledger entry that recorded the event the activity carries, so that divergence between the canonical log and a participant's replica is observable rather than silent. Derived from CONCERN-2657 and ADR-0080.

ID Priority Requirement Related
OX-14-002 MUST NOT A canonical CaseLedgerEntry commit MUST NOT be deferred until delivery of the corresponding outbound activity is confirmed.

Gating the commit on delivery makes an actor's own decision history hostage to the network, inverts the guards-then-commit-then-effects ordering CLP-10-006 requires, and creates an unanswerable partial-delivery question when some recipients succeed and others fail. Delivery confirmation is a transport-level receipt and is not agreement to the delivered content; the two layers stay separate.

Signing

Requirements for signing the activities an actor sends and verifying the activities it receives, using object-level proofs carried inside the activity (FEP-8b32) so that a proof stays checkable after a relay or a ledger commit. HTTP Signatures and production key handling are out of scope here (ENC-01, OX-10).

Proofs on Sent Activities

ID Priority Requirement Related
SIG-01-001 MUST Every activity an actor sends MUST carry a proof made with its author's key.

A receiver cannot otherwise tell who wrote an activity, so any client could post an activity in another actor's name (#509). The proof sits inside the activity, so it still shows who wrote the content after the CASE_MANAGER relays it or commits it to the ledger, which a signature on one HTTP delivery cannot show.
SIG-01-002 MUST A proof MUST be a DataIntegrityProof using the eddsa-jcs-2022 cryptosuite, with proofPurpose assertionMethod and a verificationMethod naming a key in its author's actor profile.

Signer and verifier must agree on one proof form, or a correct proof is refused. FEP-8b32 with eddsa-jcs-2022 (Ed25519 over the RFC 8785 canonical form) is the form ActivityPub implementations use for object integrity, and naming the key by the author's profile tells the receiver where to get it (SIG-02-001).
Extends: SIG-01-001
SIG-01-003 MUST A proof MUST cover the whole activity as sent, every nested object included, except the proof itself.

A proof that covers only part of an activity lets anyone change the rest without detection. The objects nested in an activity carry most of what a receiver acts on, such as a report's content or a ledger entry's snapshot.

Key Discovery

ID Priority Requirement Related
SIG-02-001 MUST A receiver MUST take the key that verifies a proof only from the author's actor profile, held as a copy or fetched.

A key the receiver got anywhere else, such as from the activity itself or from a third actor, proves nothing about the author: anyone can sign with a key they made and name it. The author's profile is where the author's identity is already published, so it is the one source the receiver can trust as far as it trusts the author's id.
SIG-02-002 MUST An actor MUST serve its actor profile, its key included, to a request that carries no proof or signature.

A receiver fetches the author's profile to get the key that verifies the author's proof. Demanding a proof on that fetch would need a key the requester may not have yet, so key discovery could never start.

Verification and Refusal

ID Priority Requirement Related
SIG-03-001 MUST A receiver MUST verify an activity's proof before it acts on any of the activity's content.

Content acted on before verification has already been trusted: a forged activity could change state, be stored or be relayed before its refusal. Verifying first means a refused activity leaves nothing behind.
SIG-03-002 MUST A receiver MUST refuse an activity whose proof is missing or does not verify.

Verification that admits an unsigned activity protects nothing, since a forger simply leaves the proof out. The refusal holds in every deployment, test and demo: a switch that turns it off becomes the way a test passes and a deployment is left open.
Depends on: SIG-03-001

Proofs in the Case Ledger

ID Priority Requirement Related
SIG-04-001 MUST The CASE_MANAGER MUST keep the sender's proof, unchanged, in the payloadSnapshot of the ledger entry that records a received activity.

A replica acts on a participant's words that the CASE_MANAGER delivers. Only the participant's own proof, kept in the snapshot, lets the replica check that the participant wrote them; a snapshot without it asks the replica to trust the CASE_MANAGER for what another actor said. The snapshot is the activity as received (VM-08-003), so dropping the proof would also change it.
SIG-04-002 MUST A replica MUST refuse the whole Announce(CaseLedgerEntry) when a proof it needs is missing or fails to verify. These are the CASE_MANAGER's proof on the Announce and, when the payloadSnapshot's actor is not the CASE_MANAGER, the author's proof on the snapshot.

The CASE_MANAGER's proof shows the entry came from the case's authority; the author's proof shows the participant wrote the act the entry records. Applying the entry on either alone would let a forged act enter the case through a genuine relay, or a genuine act be replayed by a forger. Refusing the whole entry keeps the replica's ledger a prefix of the CASE_MANAGER's.

Encryption

Requirements for encrypted messaging and actor key management using ActivityPub extension conventions. Ensures that sensitive vulnerability information can be protected in transit between actors.

Key Management

ID Priority Requirement Related
ENC-01-001 MUST Each actor MUST generate a unique asymmetric key pair when its identity is first provisioned.

Key material binds to an actor identity, not to a case. An actor that enacts CVDRole.CASE_MANAGER for several cases uses one key pair for all of them, so per-case key separation is a consequence of deployment topology rather than a key-binding rule. Regenerating a key pair would invalidate any peer's cached public key and break encrypted communication mid-case. See notes/encryption.md for the topology discussion.
Implements: VP-15-004
ENC-01-002 MUST Each actor MUST publish its public key in its actor profile as a Multikey listed under assertionMethod.

Peers need an actor's public key to verify the proofs it signs (SIG-02-001). assertionMethod is where an FEP-8b32 verifier looks for the key a proof's verificationMethod names, so no separate key-exchange channel is needed.
ENC-01-004 MUST NOT An implementation MUST store each private key securely, and MUST NOT write one to a log or include it in an API response.

Anyone who obtains an actor's private key can read messages encrypted to it, including embargoed vul details, and can forge activities in its name. Logs and API responses are copied and retained widely, so a key that appears in them must be treated as disclosed.
ENC-01-005 MUST An actor's asymmetric key pair MUST be persisted and reused across process restarts for the lifetime of that actor identity.

Regenerating on restart would invalidate any peer's cached public key and break encrypted communication mid-case.
Refines: ENC-01-001
ENC-01-006 MUST NOT A new key pair MUST NOT be generated on process resumption for an existing actor identity.

Generating a new key pair on restart breaks any encrypted channel established with the previous key, invalidating cached public keys held by case participants.
Refines: ENC-01-001

Message Encryption

ID Priority Requirement Related
ENC-02-001 MAY Case participants MAY encrypt messages sent to the CASE_MANAGER using an encryption key the CASE_MANAGER publishes in its actor profile.

Messages to the CASE_MANAGER can carry embargoed vul details that intermediaries must not read in transit. Encryption is optional because transport security can be enough for a deployment and no encryption scheme is yet standardized (ENC-02-002).
Implements: VP-15-004
ENC-02-002 SHOULD When sending messages to case participants, the CASE_MANAGER SHOULD encrypt each outbound message individually to an encryption key the recipient publishes in its actor profile.

The specific encryption scheme (e.g., ECDH key agreement + AES-256-GCM, RSA-OAEP) is intentionally deferred pending a protocol-level agreement. Until a scheme is standardized, the choice is implementation-defined; interoperability between independently-built implementations is not yet a requirement.
Implements: VP-15-004