- Shipped
- August 9, 2026 at 2:05 AM UTC
- Author
- Kamo
- Commit
- 94e3ea5
SecurityModelMarketController read and mutated security-model market attachments with no session check, no org scoping and no right — any caller could pass any modelId and reshape another organization's branch types, including attaching a gated vertical. Every handler now resolves the caller's org, asserts the model belongs to it under CONFIGURE_SYSTEM, and add() runs the vertical through assertCommerceTypeAllowed so a model cannot become a side door that grants mortgage or personal loans to its child orgs. GET /pos/config returned every active market and a separate DISTINCT of commerce types, both unfiltered — and the pipeline reads its tabs and quick actions from exactly there, so an org that had lost MLOS still got its MORTGAGE tab back. It now applies the same entitlement filter as the commerce-markets list and derives the engagement types from the filtered markets rather than a query that would reinstate the type just removed. **************** matched a canonical UUID, which is strictly narrower than the UUID.fromString the handlers bind with — that accepts unpadded groups like 1-2-3-4-5, so a request could name a real market in a form the gate did not recognise. The segment is matched loosely and the same parse the handler performs decides. /commerce-vendor-categories is a second prefix onto the commerce surface; the per-market interceptor cannot see it because the vertical arrives as a parameter, not a path segment. It is now behind the POS app gate and each handler refuses a vertical the org is not entitled to. Also serializes the catalog's verdict on both feature payloads, so the tenant Apps tab can stop inferring it from development stage.