Skip to content

Catalog is the trust root for asset checksums; pin against a vendored floor #30

Description

@skoudoro

Context

Since #20, polyxios/fetcher.py resolves every asset through a models.json catalog fetched at runtime from https://raw.githubusercontent.com/fury-gl/polyxios-data/master/models.json. Asset checksums come from that catalog rather than being pinned in the source tree (they previously were, in _PACKAGES).

That trade was deliberate — a live catalog means newly published assets are picked up without cutting a polyxios release — but it moves the trust root out of the reviewed code, and the sha256 check no longer proves anything about provenance.

Not urgent, and not an open exploit. Filing so it isn't forgotten.

What the checksum currently proves

That the bytes downloaded match what the catalog said at that moment. Nothing more. The same actor publishes the asset and its checksum, and an automated step rewrites both together, so anyone able to write to fury-gl/polyxios-data can swap them in one move and every client accepts the result. The check defends against a corrupted transfer or a stale CDN edge — real, but limited.

Note also that #20's stale-cache fix (a cached file is reused only while its checksum still matches the current catalog) means a rewritten catalog now propagates to machines that already hold the file. Correct behavior for a legitimate re-release; it also widens the swap window. Layer 1 below closes that.

Severity

These are sample meshes fed to polyxios codecs. The realistic ceiling is parser exploitation, disk exhaustion, or archive path traversal — the last of which is already fixed in #20 (_safe_extract_zip), along with https-only enforcement on catalog URLs. Defense in depth, not an incident.

Proposed work (client side)

Layer 1 — vendor the catalog as a floor. No data-repo change, no new dependency. models.json is ~78 KB / 277 files; ship it in the wheel. At runtime the remote catalog may add entries but may not redefine the sha256 of a filename already present in the vendored floor — mismatch refuses the download with a clear error. Every asset that existed at release time then becomes pinned as strongly as the wheel itself; new assets keep the current weaker model until the next release absorbs them.

Layer 2 — rollback and freeze protection. Once fury-gl/polyxios-data emits version / generated / expires (see the companion issue), store the highest catalog version seen under ~/.polyxios/ and refuse anything lower; warn once past expires. ~20 lines, and it's the two cheapest guarantees TUF offers.

Layer 5 (optional, later) — verify a catalog signature. Only signatures give provenance rather than integrity. Ed25519/minisign needs cryptography or PyNaCl as an optional extra (verify when installed, warn when not), and the private key must live outside the data repo or a repo compromise takes key and payload together. Sigstore keyless via GitHub OIDC avoids key custody entirely at the cost of a heavier client dependency.

POLYXIOS_MODELS_URL already exists as an escape hatch for anyone wanting to pin the catalog to an immutable raw URL today.

Related

Happy to convert this to a private security advisory instead if you'd rather not track it in the open.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions