Skip to content

AuthoringMetaV2::fetch_for_contract trusts subgraph meta bytes without checking them against the describedByMetaV1 hash #210

Description

@thedavidmeister

Unit

crates/cli/src/meta/types/authoring/v2.rsAuthoringMetaV2::fetch_for_contract (AMT group g3-graphql-query-processing).

Intent oracle

IDescribedByMetaV1::describedByMetaV1() returns the hash identifying the contract's authoring meta; the metaboard subgraph is queried by that hash (get_metabytes_by_hash). The hash is the binding between the on-chain claim and the off-chain bytes — RainMetaDocumentV1Item::hash implements exactly this keccak256 binding elsewhere in the crate.

Violated property

The bytes returned by the subgraph are cbor-decoded and converted without ever being hashed:

let metas = subgraph_client.get_metabytes_by_hash(&metahash).await...?;
let meta = RainMetaDocumentV1Item::cbor_decode(metas[0].as_slice())...?[0].clone().try_into()...?;

A metaboard endpoint (or a compromised/buggy indexer behind it) can serve arbitrary words for any hash and the fetch succeeds. Additionally only metas[0] is consulted; further entries under the same hash are ignored without any consistency check.

Verified repro

meta::types::authoring::v2::tests::test_fetch_for_contract_success (added in the AMT coverage PR) mocks describedByMetaV1() returning 0x1111…11 and a metaboard serving cbor bytes whose keccak256 is not that hash — the fetch returns the words without complaint.

Triage framing

The metaboard URL is caller-supplied and may be considered trusted, in which case this is by design; flagging because verifying keccak256(meta_bytes) == metahash is cheap, the crate already has the hashing primitive, and the current behaviour silently converts a content-addressed lookup into a trust-the-server lookup. Not adjudicating here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    adversarialFound by adversarial review/mutation testingauditAudit finding; counted by the org health scan

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions