Problem
spec/content-marking-v1.md says the assertion's record object follows C2PA's hashed-ext-uri-map: a URI plus a hash of the referenced bytes.
The reference implementation currently treats record.url as a truthiness check only.
Producer:
if not url:
raise ContentMarkingError(...)
Consumer:
if not isinstance(ref, dict) or not ref.get("url"):
raise ContentMarkingError(...)
That means truthy non-string values can be emitted or accepted as the record URL, and arbitrary non-HTTP strings are also accepted. Examples include True, 1, [1], {"x": 1}, "not a url", and "ftp://example.test/record.json".
This is a boundary mismatch in both directions: build_assertion() can produce a value outside the external-reference shape the companion spec says it implements, and verify_assertion() can accept the same shape from a peer assertion.
Proposed change
Establish record.url as an absolute HTTP(S) URI at both producer and consumer boundaries before it is used in the assertion or in verifier diagnostics.
A focused regression matrix should hold:
https://registry.example/record.json -> accepted;
http://registry.example/record.json -> accepted;
- boolean/integer/list/object values -> refused;
- whitespace or arbitrary text -> refused;
ftp://... -> refused;
- HTTP(S) URI without a host -> refused.
The implementation should avoid inventing a broader URI policy than the C2PA external-reference contract requires.
Scope
Content-marking producer/consumer validation only. No change to hashing, Trust Record verification, C2PA signature handling, or TRACE wire format.
AI-assistance disclosure: ChatGPT assisted with source triage, adversarial-case design, and drafting. altrudev reviewed the bounded claim and remains responsible for the contribution.
Problem
spec/content-marking-v1.mdsays the assertion'srecordobject follows C2PA'shashed-ext-uri-map: a URI plus a hash of the referenced bytes.The reference implementation currently treats
record.urlas a truthiness check only.Producer:
Consumer:
That means truthy non-string values can be emitted or accepted as the record URL, and arbitrary non-HTTP strings are also accepted. Examples include
True,1,[1],{"x": 1},"not a url", and"ftp://example.test/record.json".This is a boundary mismatch in both directions:
build_assertion()can produce a value outside the external-reference shape the companion spec says it implements, andverify_assertion()can accept the same shape from a peer assertion.Proposed change
Establish
record.urlas an absolute HTTP(S) URI at both producer and consumer boundaries before it is used in the assertion or in verifier diagnostics.A focused regression matrix should hold:
https://registry.example/record.json-> accepted;http://registry.example/record.json-> accepted;ftp://...-> refused;The implementation should avoid inventing a broader URI policy than the C2PA external-reference contract requires.
Scope
Content-marking producer/consumer validation only. No change to hashing, Trust Record verification, C2PA signature handling, or TRACE wire format.
AI-assistance disclosure: ChatGPT assisted with source triage, adversarial-case design, and drafting.
altrudevreviewed the bounded claim and remains responsible for the contribution.