From Wave 5 security audit, finding F-O-01. Severity: high.
Threat model
The weekly `.github/workflows/spec-sync.yml` cron:
- Has `permissions: contents: write, pull-requests: write` (
spec-sync.yml:9-11).
- Calls `scripts/sync_spec.py` which downloads YAML from `https://docs.kalshi.com/openapi.yaml\` and `/asyncapi.yaml` with no signature/hash pinning (`scripts/sync_spec.py:13-17`).
- Feeds the YAML to `scripts/generate.py` (`datamodel-code-generator`), which writes Python that the test suite imports (`spec-sync.yml:135-137`).
- Runs full `uv run pytest tests/ -v` against the generated code (`spec-sync.yml:147-149`).
- Opens a PR via `peter-evans/create-pull-request`.
If a maintainer ever enables auto-merge on that PR, or hand-merges without auditing `_generated/models.py`, a compromise of upstream (MITM on `docs.kalshi.com`, or a malicious change merged into Kalshi's published spec) becomes a path to PyPI-published malicious code via the existing release workflow (release.yml triggers on tag push).
Mitigation options
- (a) Pin a published checksum/signature for the spec files and verify before regen. Kalshi would need to publish a checksum or sigstore bundle alongside the spec; this is upstream-dependent.
- (b) Keep auto-PR but require human approval plus an explicit "I read `_generated/models.py`" check (e.g., a checkbox in the PR template the workflow enforces with a status check).
- (c) Drop the writable workflow entirely: gate the PR generation behind a workflow with only `contents: read` and post the diff as an issue comment, never as a writable branch. A maintainer manually opens a PR for genuine changes.
Option (c) is the safest. (b) is the smallest change. The existing SHA-pinning of third-party actions in this workflow is the right pattern — extend the principle to the content being merged.
Out of scope here
From Wave 5 security audit, finding F-O-01. Severity: high.
Threat model
The weekly `.github/workflows/spec-sync.yml` cron:
spec-sync.yml:9-11).If a maintainer ever enables auto-merge on that PR, or hand-merges without auditing `_generated/models.py`, a compromise of upstream (MITM on `docs.kalshi.com`, or a malicious change merged into Kalshi's published spec) becomes a path to PyPI-published malicious code via the existing release workflow (
release.ymltriggers on tag push).Mitigation options
Option (c) is the safest. (b) is the smallest change. The existing SHA-pinning of third-party actions in this workflow is the right pattern — extend the principle to the content being merged.
Out of scope here