v0.1.25.50 — security: tenant webhook event_categories boundary
Security release. Closes an authorization gap in tenant self-service webhook subscriptions.
Security
- Tenant-plane webhook
event_categoriesare now validated against the tenant-accessible boundary. Tenant self-service webhook create and update rejected admin-onlyevent_types(api_key/policy/webhook/system), but did not validateevent_categories— and category matching is additive with type matching. A tenant key could create or update a subscription with one allowedevent_typeplus"event_categories": ["api_key"](or policy/webhook/system) and receive admin-only event classes for its tenant. Both create and update now reject admin-only categories with 400INVALID_REQUEST, deriving the boundary from a singleEventCategory.isTenantAccessible()source (governance spec revision v0.1.25.38, runcycles/cycles-protocol#126). Admin-plane webhook endpoints are unaffected. - Operators: audit existing tenant-plane subscriptions created on 0.1.25.49 and earlier for smuggled admin-only categories, and for the match-ALL rows below. A copy-pasteable
redis-cli+jqrecipe (flagging bothADMIN_CATEGORIESandMATCH_ALLrows, with the admin-provisioned-provenance caveat) is in CHANGELOG.md[0.1.25.50]Security.
Fixed
- Empty-both match-ALL door closed.
WebhookService.updateapplied an emptyevent_types: []verbatim; with no categories, the matcher's empty-both branch made the subscription match every event class (admin-only included). Update now rejects a change that would leave a subscription with neitherevent_typesnorevent_categories(both planes; the state is not creatable on either). Category-only subscriptions remain legal.
Follow-up (tracked, not in this release): whether a tenant should retain admin-only categories on a legacy/admin-created subscription it owns is a separate provenance/ownership question — tracked as #209.
Compatibility
- No HTTP request/response schema, Redis data model, or Lua change. Requests that previously smuggled admin-only categories now return 400; legitimate tenant-accessible categories are unaffected. Legacy offender rows keep delivering until repaired — see the audit recipe.
- Full-stack compose bundles
cycles-server0.1.25.47 andcycles-server-events0.1.25.22.
1,566 tests green including integration + contract validation against governance spec v0.1.25.38; JaCoCo ≥95% on all modules; external security review (codex) SHIP. Full details: CHANGELOG.md [0.1.25.50], AUDIT.md, PR #208.