Skip to content

security: decide the path for grain authenticity (COSE signing) before building on the dormant scaffolding #77

Description

@sathish-mg

Summary

Design a real grain-authenticity (signing) story for Areev — and decide how far to take it — before anyone (human or AI assistant) tries to "finish" the dormant COSE scaffolding that already sits in areev-core.

This came up because an AI pair-programming session, working through a security review, was about to implement this and stopped after finding an explicit guardrail in the repo. Filing it as a real ticket so the decision gets made deliberately instead of by whoever next stumbles into the scaffolding.

Current state (verified against code)

crates/areev-core/CLAUDE.md says, verbatim:

The signing feature is referenced in code (serialize_grain_signed, crate::crypto::signing, coset) but there is no crypto module, dep, or feature declaration — dormant scaffolding for a future areev-crypto. Don't try to build it.

That's accurate:

  • crates/areev-core/src/format/serialize.rs (~lines 113-138) has serialize_grain_signed, #[cfg(feature = "signing")], with a detailed doc comment: it sets an is_signed flag (bit 0 of byte 1), recomputes the content hash over the blob with that flag set, then COSE-Sign1-wraps it with org_context bound into the AAD "to prevent cross-org replay attacks." This is a carefully designed shape, not a stub.
  • crates/areev-core/src/format/deserialize.rs (~lines 13-38) has unwrap_if_cose, which detects a COSE Sign1 envelope by its leading CBOR byte (0x84) and unwraps it — but explicitly does not verify the signature (doc comment: "no signature verification — use crypto::signing::verify_grain separately if verification is required").
  • Both reference crate::crypto::signing::* and the coset crate. Neither exists. There is no crypto module in areev-core, and coset is not a dependency anywhere in the workspace.
  • crates/areev-core/Cargo.toml (~lines 15-21) declares signing = [] as an empty feature, with the comment: "Dormant capability gates: the code carries #[cfg(feature = ...)] hooks for these but they are not wired up yet... enabling them is future work."
  • Net effect: turning the signing feature on today would fail to compile (the code paths reference things that don't exist). This is intentional scaffolding for a future crate, not a working feature with a flag someone forgot to flip.

Why it's not a quick finish (the three real blockers)

  1. No trust model. docs/areev-governed-agents-proposal.md (~lines 674-678) ties real verification to a "host-configured author key" registry that doesn't exist yet: "When COSE signing lands (named dependency), the registry upgrades to signature verification against host-configured author keys." Without deciding who signs, how a host declares which authors/keys are trusted, and how rotation/revocation works, a signature check has nothing meaningful to check against.
  2. The spec isn't finalized. Areev is positioned as the reference implementation of OMS. docs/cal-all-you-need-proposal.md (~lines 158-166) calls COSE signing "OMS §9 ... the high-assurance upgrade path, not v1" — i.e. the external spec hasn't settled the signing semantics. Areev's canonical serialization is deliberately frozen for exactly this class of risk (CLAUDE.md invariant deps: bump logos from 0.14.4 to 0.16.1 #2: changing it "silently changes every content address and breaks OMS conformance"). Building envelope details ahead of the spec risks the same failure mode later.
  3. New dependency, core crate. coset would be the first crypto-format dependency in areev-core, the crate everything else in the workspace depends on — against the stated "dependency-light by policy... think twice before adding a dependency" stance (CLAUDE.md invariant deps: bump pyo3 from 0.29.0 to 0.29.2 #6).

A secondary, real-but-not-primary consideration: Areev gates releases on hard latency numbers (voice_loop's 50ms-cadence gate; a ~200µs recall gate referenced in docs/postgres-backend-proposal.md). Ed25519 (or similar) sign/verify at write- and import-time isn't free at scale on a bulk bundle import and would need to be benchmarked against crates/areev-store/examples/bench.rs before being made mandatory-by-default. This is not documented anywhere as the reason the feature was deferred — no rationale survives in git history (the repo's history is a single squashed "Initial commit: Areev 1.0.0," so the original design conversation isn't recoverable) — but it's a real cost worth planning for regardless of why the deferral happened.

What this closes

docs/security-model.md's "Known limitations in transit" section: "⚠️ Integrity, not authenticity. Content addressing detects corruption and tampering, but does not verify who authored a grain... Only sync with peers you trust." Real signing is what upgrades that from "detect tampering" to "verify provenance," and is the prerequisite docs/areev-governed-agents-proposal.md §7 names for the host code-approval registry to become signature-backed instead of hash-allowlist-only.

Options discussed (decide which to pursue)

  1. Design now, build later (recommended starting point). Write an ARCHITECTURE.md §10 decision entry plus a concrete, scoped implementation plan: key management model (who signs, host-configured trusted-author config shape, rotation/revocation), the coset dependency addition, where verification wires into import/sync, and an explicit note on how this interacts with OMS §9 (build to the current draft with a documented migration path, or wait). No crypto code lands in this pass.
  2. Build a minimal real version now. Stand up an actual areev-crypto module + coset dependency + real sign/verify, scoped narrowly (e.g. local areev verify / bundle import only, not the full trusted-author registry). Real capability sooner, but more surface area in one pass, and ahead of the OMS spec settling.
  3. Skip full signing; close the gap a lighter way. Leave the COSE scaffolding untouched as documented future work, and instead strengthen what already exists — areev verify's hash-chain checking, areev audit export's tamper-evidence — as a stop-gap authenticity signal that's explicit about being weaker than real signatures, with no new dependency.

Acceptance criteria

  • A decision is recorded (ARCHITECTURE.md §10 entry at minimum) on which option to pursue and why.
  • If design-now: a scoped implementation plan exists that a future PR can execute directly, including the key-management shape and the OMS §9 relationship.
  • crates/areev-core/CLAUDE.md's "don't try to build it" gotcha is updated once a direction is chosen, so it stops being a trap for the next person (human or AI) who reads it.

Context

Surfaced during a conversational security/enterprise-readiness review. Related: #83

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsecuritySecurity, authz, crypto, and hardening work

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions