Filed from signing security review 2026-04-14. Severity: LOW.
Current state
`deployment_signing_keys` schema has `active` (true/false) + `rotated_at` timestamp. There's no way to mark a key as compromised — bundles signed with it should not be trusted even though the key is inactive.
`SigningService.verify()` happily verifies any bundle whose `key_id` matches a row, regardless of operator-known compromise.
Recommendation
Schema change:
- `revoked` BOOLEAN NOT NULL DEFAULT false
- `revoked_at` TIMESTAMP WITH TIME ZONE
- `revocation_reason` TEXT
Behavior change:
- `verify()` returns false (with reason in response payload) for bundles signed with a revoked key
- New endpoint `POST /api/signing/keys/{id}/revoke` (SUPER_ADMIN only) accepting a reason
- Revocation event written to audit log
References
- Source: `docs/SIGNING_SECURITY_REVIEW_2026-04-14.md`
- Module: `backend/app/services/signing/signing_service.py`
- Migration: `backend/alembic/versions/20260413_0500_051_add_signing_keys.py` (extend)
Filed from signing security review 2026-04-14. Severity: LOW.
Current state
`deployment_signing_keys` schema has `active` (true/false) + `rotated_at` timestamp. There's no way to mark a key as compromised — bundles signed with it should not be trusted even though the key is inactive.
`SigningService.verify()` happily verifies any bundle whose `key_id` matches a row, regardless of operator-known compromise.
Recommendation
Schema change:
Behavior change:
References