chore(security): Ed25519 signing review + 3 fixes#397
Merged
Conversation
Mandatory security review per Q1-Q3 plan governance. Tooling clean: Bandit 0 findings, Semgrep 0 findings on 239 rules. Manual review found 5 items. Fixes in this PR: SEC-SIGN-01 (HIGH): private key fallback to plain base64 - signing_service.py silently stored private keys as plain base64 when EncryptionService was missing. Production deploys that misconfigured the service got insecure-at-rest storage with no signal. - Fix: hard-fail in generate_key() and sign_envelope() unless explicit OPENWATCH_SIGNING_DEV_MODE=true env var is set (test/dev only). - Spec AC-8 was being violated whenever the fallback path was hit. SEC-SIGN-02 (MEDIUM): race condition on key generation - generate_key() ran UPDATE then INSERT in two separate statements with no transaction wrapping. Concurrent rotations could leave two rows with active=true. - Fix: SELECT ... FOR UPDATE on the active row before deactivating, taking a row-level lock that serialises concurrent calls. SEC-SIGN-03 (MEDIUM): silent signing failure on audit export - audit_export.py caught all exceptions from sign_envelope() and proceeded with an unsigned export. Auditors downloaded what they thought was signed evidence without any signal of the failure. - Fix: write explicit signed_bundle: null + signing_error fields to the export so the unsigned state is machine-detectable from the artifact itself. Follow-ups filed (LOW, not exploitable): - SEC-SIGN-04: verify endpoint DoS surface (per-endpoint rate limit) - SEC-SIGN-05: no key revocation flag (rotation-only today) Tests: added regression test for SEC-SIGN-01 to enforce the dev-mode gate convention and prevent future silent fallbacks. Review document: docs/SIGNING_SECURITY_REVIEW_2026-04-14.md
remyluslosius
added a commit
that referenced
this pull request
Apr 14, 2026
Direct action from the Kensa↔OpenWatch coordination. Per-transaction
evidence envelope signing moves to Kensa (where the evidence originates);
OpenWatch signs only aggregate artifacts it itself produces.
Kensa response §2.2 confirmed the trust-layer boundary:
Kensa signs: per-transaction evidence envelope at capture/execute time.
Attests: "This execution happened on this host at this time."
OpenWatch signs: audit exports, quarterly posture reports, State-of-
Production releases.
Attests: "OpenWatch aggregated this data from N hosts and produced
this artifact."
Changes:
- Remove POST /api/transactions/{id}/sign endpoint. Handler function
deleted; module docstring documents the removal and the boundary.
- SigningService docstring rewritten with a trust-layer boundary
diagram and a clear "aggregate artifacts only" statement.
- specs/services/signing/evidence-signing.spec.yaml bumped to v2.0:
- Former AC-6 (per-transaction sign endpoint) replaced with
AC-6 for /api/signing/verify
- New AC-9: per-transaction signing explicitly out of scope
- AC-7/AC-8 expanded with the SEC-SIGN-01 dev-mode gate and
SEC-SIGN-03 machine-detectable unsigned-state guarantees
- context: block documents the scope-narrow rationale and
Kensa convergence at Week 22 (Kensa.VerifyEnvelope)
- Regression tests: AC-9 added enforcing the endpoint is gone and the
module docstring names the boundary. AC-8 tightened with the explicit
signed_bundle=None + signing_error assertions from audit_export.
- docs/SIGNING_SECURITY_REVIEW_2026-04-14.md updated with a "Scope
narrow" section at the top documenting what was removed, what
remains, and how OpenWatch verifies Kensa-signed envelopes at
Kensa Week 22.
No change to the five original security findings (SEC-SIGN-01/-02/-03
remain fixed in PR #397; SEC-SIGN-04/-05 remain open as #395/#396).
Spec coverage: 824/824 ACs (was 823, +1 for AC-9).
5 tasks
remyluslosius
added a commit
that referenced
this pull request
Apr 14, 2026
…cts (#400) Direct action from the Kensa↔OpenWatch coordination. Per-transaction evidence envelope signing moves to Kensa (where the evidence originates); OpenWatch signs only aggregate artifacts it itself produces. Kensa response §2.2 confirmed the trust-layer boundary: Kensa signs: per-transaction evidence envelope at capture/execute time. Attests: "This execution happened on this host at this time." OpenWatch signs: audit exports, quarterly posture reports, State-of- Production releases. Attests: "OpenWatch aggregated this data from N hosts and produced this artifact." Changes: - Remove POST /api/transactions/{id}/sign endpoint. Handler function deleted; module docstring documents the removal and the boundary. - SigningService docstring rewritten with a trust-layer boundary diagram and a clear "aggregate artifacts only" statement. - specs/services/signing/evidence-signing.spec.yaml bumped to v2.0: - Former AC-6 (per-transaction sign endpoint) replaced with AC-6 for /api/signing/verify - New AC-9: per-transaction signing explicitly out of scope - AC-7/AC-8 expanded with the SEC-SIGN-01 dev-mode gate and SEC-SIGN-03 machine-detectable unsigned-state guarantees - context: block documents the scope-narrow rationale and Kensa convergence at Week 22 (Kensa.VerifyEnvelope) - Regression tests: AC-9 added enforcing the endpoint is gone and the module docstring names the boundary. AC-8 tightened with the explicit signed_bundle=None + signing_error assertions from audit_export. - docs/SIGNING_SECURITY_REVIEW_2026-04-14.md updated with a "Scope narrow" section at the top documenting what was removed, what remains, and how OpenWatch verifies Kensa-signed envelopes at Kensa Week 22. No change to the five original security findings (SEC-SIGN-01/-02/-03 remain fixed in PR #397; SEC-SIGN-04/-05 remain open as #395/#396). Spec coverage: 824/824 ACs (was 823, +1 for AC-9).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mandatory security review per Q1-Q3 plan governance.
Summary
Manual review of the Ed25519 evidence signing service, routes, and audit-export integration. Tooling clean (Bandit + Semgrep 0 findings). Manual review found 1 HIGH, 2 MEDIUM, 2 LOW. HIGH and both MEDIUMs fixed in this PR; LOWs filed as #395 and #396.
Findings fixed
Findings deferred
Tool results
Manual review — positive controls confirmed
Test coverage
Added regression test `test_no_silent_plain_base64_fallback` in `test_evidence_signing_spec.py` (AC-8 section) that enforces the dev-mode gate convention. Source-inspection pattern matches the codebase convention.
`check-spec-coverage.py --enforce-active`: 813/813 ACs covered.
Governance carve-outs (not addressed by automated review)
Test plan