Skip to content

Author attestation is a CG-independent bearer credential once it authorizes publish (#1689 follow-up) #1972

Description

@Jurij89

Follow-up to #1689 / PR #1971, deferred deliberately there so the authorization fix stayed reviewable. Raised independently by otReviewAgent on PR #1971, which reached the same conclusion from the diff alone.

What changed, and why that matters here

PR #1971 makes KnowledgeAssetsLifecycle._executePublishCore authorize a publish when either the paying principal (msg.sender) or the EIP-712-attested author is an authorized publisher for the CG. That fixes #1689 — a curated-CG curator can finally delegate payment to a funded operational wallet.

It also promotes the author attestation from an attribution artifact to an authorization credential. The attestation was never designed to carry that weight.

The gap

AuthorAttestation binds exactly four fields:

"AuthorAttestation(bytes32 merkleRoot,address authorAddress,uint8 schemeVersion,uint256 reservedKaId)"

plus the EIP-712 domain (chainId, verifyingContract). It binds:

So a seal is a bearer token, valid indefinitely until its slot is minted, and the holder — not the author — chooses the destination CG, epochs, and isImmutable in calldata.

Reachability

The seal is persisted to the CG's _meta graph at finalize time (dkg-agent-publish.tsbuildAssertionSealQuads, fields authorAttestationR / authorAttestationVS) and replicated peer-to-peer over the durable _meta sync lane. The responder serves _meta rows with no predicate filtering, so the signature ships verbatim to any authorized syncing peer. For a public CG, authorizeSyncRequest returns true unconditionally — the attestation is world-readable. For a private CG the barrier is CG membership, i.e. exactly the co-tenants best placed to grief a curator.

StorageACKs are not a barrier: core nodes issue them with no authorization check on the requester.

Impact — bounded, but the sharp edges are permanent

A holder of a seal can pay to publish that content into a CG where the author is authorized:

  • The reservedKaId slot is consumed permanently and kaToContextGraph binding is irreversible, so the author can never republish that slot to the CG they intended.
  • The attacker chooses isImmutable, which can permanently freeze the KA against all future updates.
  • The attacker chooses epochs.

Bounding it honestly:

Net incremental exposure: curated/PCA CGs where the author is the authority or an affiliated agent.

Options

  1. Add a deadline to AuthorAttestation — cheapest meaningful mitigation. Bounds the bearer window without reversing Clarify knowledge asset lifecycle when SWM share succeeds without a seal but VM publish requires finalization #1116's CG-independence. Changes the typehash, so it needs client/contract lockstep.
  2. Re-bind contextGraphId — closes it completely, but reverses Clarify knowledge asset lifecycle when SWM share succeeds without a seal but VM publish requires finalization #1116, whose motivation was sealing before CG registration.
  3. A scoped delegation/consent record — cleanest model, but needs new storage, i.e. redeploying ContextGraphStorage and migrating live CG state.
  4. Withhold authorAttestationR/VS from the durable-_meta sync responder — orthogonal, reduces reachability, and can ship independently of any contract change.

Timing argument for (1) or (2): #1971 already requires a KnowledgeAssetsLifecycle redeploy, and rotation invalidates every outstanding attestation regardless (the KAL address is in the EIP-712 domain separator). That makes it the cheapest moment to change the attestation shape — the migration cost is already being paid.

Related, found during the same analysis

  • CG escrow / PCA discount when payer ≠ CG owner. _useCgEscrow is owner-scoped and the PCA discount reads agentToAccountId(msg.sender), so the operators fix(protocol): authorize curated publish by attested author OR payer (#1689) #1971 unblocks silently forfeit their prepaid escrow and discount. Left on msg.sender deliberately — re-keying to the author would let a seal holder spend the author's funds — but the silent full-price fall-through deserves a warning surface.
  • StorageACK requester authorization, and the swmGraphId != contextGraphId remap that lets a requester read data under one CG while targeting another in the ACK digest.
  • Update-path attestation replay. UpdateAuthorAttestation binds no nonce or version, and DKGKnowledgeAssets pushes merkle roots with no duplicate/monotonicity guard. Pre-existing, independent of fix(protocol): authorize curated publish by attested author OR payer (#1689) #1971.

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority:highMust-fix: protocol correctness, security, economics, or headline flow broken

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions