Static read-through audit of crates/dpp-domain. Five verified findings — the most severe batch in dpp-core.
1. patch_fields() allows arbitrary JSON deltas to bypass the state machine
Location: src/ports/passport_repo.rs:88 (default impl, lines 76-93)
Issue: The default patch_fields() merges an arbitrary serde_json::Value delta directly onto the serialized Passport (pm.extend(dm)) with no field allowlist, then persists it without going through PassportStatus::transition_to().
Failure scenario: A delta like {"status":"active","retentionLocked":false,"jwsSignature":"x"} bypasses the state machine entirely — it can flip a retention-locked passport back to unlocked or forge signature fields. Any adapter that doesn't override this default inherits the bypass.
2. redact() fails open and leaks confidential-tier data
Location: src/domain/passport/passport.rs:299-303
Issue: When catalog.get(key) returns None for the passport's sector, sector_data is serialized and returned unredacted. The doc comment acknowledges this ("fail-open at the domain layer") and defers enforcement to a caller-side "vault layer," but nothing in this crate enforces that such a caller always exists.
Failure scenario: Any code calling Passport::redact() directly for a sector absent from its catalog instance leaks confidential-tier sector fields to a public-tier viewer.
3. Schema-version format check is vacuously true on malformed input
Location: src/domain/passport/passport.rs:166-171
Issue: The semver check for schema_version verifies parts 0/1 are digits and part 2 is non-empty, but never checks part 2 is digits. .chars().all(...) on an empty string is vacuously true.
Failure scenario: schema_version = ".5.0" (empty major) or "1.0.abc" (non-numeric patch) both pass as "valid," later failing semver::Version parsing elsewhere and silently skipping schema validation (see finding 5).
4. Catalog registration doesn't validate its own documented invariant
Location: src/catalog/catalog.rs:161-167
Issue: SectorCatalog::register() only checks key uniqueness — never that current_schema_version is valid semver or a member of schema_versions, despite the doc requiring it.
Failure scenario: A caller loading descriptors from external JSON can register a sector with an unparseable version, which then silently skips JSON-Schema validation for every passport in that sector (see finding 5).
5. Runtime-registered schemas are invisible to validation
Location: src/domain/validation/functions.rs:19-28, mod.rs:3-4
Issue: Schema resolution goes through private OnceLock statics seeded once from embedded manifests, contradicting the doc's claim of routing through the shared VersionedSchemaRegistry.
Failure scenario: Anything registered at runtime via VersionedSchemaRegistry::register() (the documented hot-reload workflow) is never seen by Passport::validate(), which always validates against the stale embedded schema — and (per finding 3/4) an unparseable version silently skips validation entirely rather than erroring.
Static read-through audit of
crates/dpp-domain. Five verified findings — the most severe batch in dpp-core.1.
patch_fields()allows arbitrary JSON deltas to bypass the state machineLocation:
src/ports/passport_repo.rs:88(default impl, lines 76-93)Issue: The default
patch_fields()merges an arbitraryserde_json::Valuedelta directly onto the serializedPassport(pm.extend(dm)) with no field allowlist, then persists it without going throughPassportStatus::transition_to().Failure scenario: A delta like
{"status":"active","retentionLocked":false,"jwsSignature":"x"}bypasses the state machine entirely — it can flip a retention-locked passport back to unlocked or forge signature fields. Any adapter that doesn't override this default inherits the bypass.2.
redact()fails open and leaks confidential-tier dataLocation:
src/domain/passport/passport.rs:299-303Issue: When
catalog.get(key)returnsNonefor the passport's sector,sector_datais serialized and returned unredacted. The doc comment acknowledges this ("fail-open at the domain layer") and defers enforcement to a caller-side "vault layer," but nothing in this crate enforces that such a caller always exists.Failure scenario: Any code calling
Passport::redact()directly for a sector absent from its catalog instance leaks confidential-tier sector fields to a public-tier viewer.3. Schema-version format check is vacuously true on malformed input
Location:
src/domain/passport/passport.rs:166-171Issue: The semver check for
schema_versionverifies parts 0/1 are digits and part 2 is non-empty, but never checks part 2 is digits..chars().all(...)on an empty string is vacuously true.Failure scenario:
schema_version = ".5.0"(empty major) or"1.0.abc"(non-numeric patch) both pass as "valid," later failingsemver::Versionparsing elsewhere and silently skipping schema validation (see finding 5).4. Catalog registration doesn't validate its own documented invariant
Location:
src/catalog/catalog.rs:161-167Issue:
SectorCatalog::register()only checks key uniqueness — never thatcurrent_schema_versionis valid semver or a member ofschema_versions, despite the doc requiring it.Failure scenario: A caller loading descriptors from external JSON can register a sector with an unparseable version, which then silently skips JSON-Schema validation for every passport in that sector (see finding 5).
5. Runtime-registered schemas are invisible to validation
Location:
src/domain/validation/functions.rs:19-28,mod.rs:3-4Issue: Schema resolution goes through private
OnceLockstatics seeded once from embedded manifests, contradicting the doc's claim of routing through the sharedVersionedSchemaRegistry.Failure scenario: Anything registered at runtime via
VersionedSchemaRegistry::register()(the documented hot-reload workflow) is never seen byPassport::validate(), which always validates against the stale embedded schema — and (per finding 3/4) an unparseable version silently skips validation entirely rather than erroring.