Skip to content

spec: the well-known key document is unsigned, so web-host write access equals trust-root compromise #116

Description

@rrrodzilla

Summary

The key document published at /.well-known/agent-keys.json carries no
signature. Its authenticity rests entirely on the TLS connection that served
it, which makes write access to the web server equivalent to possession of the
trust root's signing key. Section 8 does not treat the publication channel as
its own threat, and none of §8.2's mitigations apply to it.

What the document is today

KeyDocument (agent-uri-attestation/src/key_document.rs:111) has three
fields and no fourth:

pub struct KeyDocument {
    trust_root: String,
    keys: Vec<PublishedKey>,
    #[serde(default)]
    revoked_keys: Vec<RevokedKey>,
}

That matches §7.2's response format, so this is a specification property rather
than an implementation gap.

Why this is not covered by §8.2

§8.2 covers a compromised signing key thoroughly: revocation on both
granularities, overlap windows, short exp, HSMs. Compromising the
publication host reaches the same outcome — minting attestations that verify
for the whole namespace — but every mitigation §8.2 offers is unavailable:

§8.2 mitigation Against a compromised publication host
revoked_keys list The attacker serves the document that carries the list
Key rotation with overlap The attacker publishes the incoming key
HSM protection The signing key was never the target
Short exp Bounds each token, not the attacker's ability to mint more

Revocation is the load-bearing one, and it inverts here: the channel a verifier
consults to learn that a key is bad is the channel the attacker controls.

§8.3 is the nearest coverage, but it addresses a different threat — an
attacker claiming a domain they do not control — and its mitigation ("DNS and
TLS provide domain authentication") is exactly what a host compromise defeats,
because the attacker is serving from the legitimate domain with a legitimate
certificate.

Why the client cannot close it

agent-uri-attestation-wellknown already enforces every check §7.2 asks for:
HTTPS-only, no redirects, caps on declared and actual body length, and the
requirement that a document name the root that served it. Each of those
defends the channel. None of them can distinguish a document the trust root
authored from one an attacker wrote to the same path, because there is nothing
in the document to distinguish them by.

This is also not something a hardened server deployment fixes. A compromised
application server is exactly as fatal as a compromised nginx.

Proposed mitigation

Sign the key document with an offline root key, so the web host never holds
signing material:

  • Add a signature field to §7.2's response format covering the document body.
  • The signing key stays offline; publication becomes a file copy.
  • Verifiers pin the root key out of band, as a deployment decision — §7.2
    already establishes that "which trust roots matter is a deployment decision".

Host compromise then degrades to denial of service and stale-document
replay, rather than namespace takeover.

Open questions

  1. Bootstrap. A self-signed document is circular: whoever writes the file
    writes the signature. The root key has to be pinned out of band for this to
    buy anything, which is real deployment cost and worth weighing against the
    threat.
  2. Replay of a stale signed document. Signing alone does not stop an
    attacker serving an older validly-signed document that predates a
    revocation. Needs a monotonic version or freshness bound, which is
    additional mechanism.
  3. Whether the cost is worth it. For a deployment where the trust root
    already runs its own infrastructure, the added key-management burden may
    exceed the risk. The alternative is to leave the design as it is and state
    the limitation explicitly in §8 so operators can decide.

At minimum, §8 should name this threat and its residual risk, even if the
signed-document mitigation is not adopted.

Scope

Specification change (§7.2 response format, new §8 subsection). Implementation
in agent-uri-attestation and agent-uri-attestation-wellknown follows from
whatever the specification settles on.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    crate:attestationagent-uri-attestationdesign-decisionNeeds a design or scope decisionsecuritySecurity hardening or vulnerability

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions