Skip to content

dpp-integrator: steel/aluminium/tyre skip GTIN checksum validation; malformed vault response recorded as success #12

Description

@LKSNDRTMLKV

Static read-through audit of crates/dpp-integrator — an unusually well-hardened bulk-upload surface (zip-bomb/dimension-bomb guards, row cap, body-size limit ahead of auth+parsing). Two verified findings.

1. GTIN accepted with zero format/checksum validation for three sectors

Location: src/domain/validate/steel.rs:29, aluminium.rs:29, tyre.rs:30
Issue: battery.rs:67-77 runs Gtin::parse(&g), enforcing 14 digits and the GS1 mod-10 check digit. Steel/aluminium/tyre instead use require_str and pass the raw string straight through (their struct fields are plain String, not Gtin). dpp-vault's Rust-level check-digit validation is explicitly scoped to SectorData::Battery only, so nothing downstream catches this either.
Failure scenario: Uploading a steel/aluminium/tyre CSV row with gtin=123 or gtin=not-a-code passes row validation and is forwarded to dpp-vault verbatim — a bad checksum on a nominally 14-digit code is never caught anywhere in the pipeline.

2. Vault response missing id is silently recorded as success

Location: src/domain/batch_runner.rs:79-88
Issue: body.get("id").and_then(|v| v.as_str()).unwrap_or("") — if the vault ever returns 2xx without a string id (contract drift, partial response), the row lands in created with passport_id: "" instead of surfacing an error.
Failure scenario: success_count overstates real success; the operator gets an unusable empty ID with no error to act on.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcomplianceRegulatory/compliance correctness issue

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions