CVE-2026-15254
This vulnerability exposes a design failure in how user-scoped shortcodes were implemented: the developer added per-user filtering as a fallback rather than a hard requirement, creating a silent bypass when the shortcode renders in unexpected contexts. The core mechanism is straightforward. The shortcode checks `get_current_user_id()` to scope data to the authenticated user, but when this returns zero — which happens in certain AJAX contexts, REST endpoints, or when WordPress hasn't fully initialized user context — the query falls through to a global fetch of all appointment records. This is the 'fails open' pattern: the scoping logic degrades to unrestricted access rather than blocking the request. What makes this urgent is the privilege gap. WordPress Contributors have `read` capability and can create draft pages containing shortcodes, but they cannot publish. The plugin assumed Contributors would only see their own appointments in normal workflows. However, a Contributor can embed the shortcode on a page that an Editor later publishes, and when any authenticated user visits that page, the soft-scoping fails and exposes ALL appointment records site-wide — names, phone numbers, email addresses, and notes for every customer. The critical distinction you're checking: user ID and capability are different security domains. The plugin scoped to user ID (the appointment owner field) without also checking capability (does this user have any right to access OTHER people's appointments?). A shortcode on a public page can be reached by any authenticated user with read access, and that user's ID might be non-zero without conferring any right to see other users' relational data. Your check should verify that the patch adds TWO gates: first, a hard capability check that fails closed when user context is missing or insufficient, and second, the user-ID scoping on the data query itself. A single user-ID check is insufficient because it was never designed to handle contexts where the calling user is authenticated but the shortcode placement wasn't authorized by someone with full editing rights. Watch for patch-induced denial of service: a hard capability check that dies() or returns empty on failure can create a new vector where Contributors can trigger page-render failures for anyone who visits pages containing the shortcode. The 'fix' trade-off is sometimes worse than the original vulnerability depending on your threat model.
Reviewed through automated stages and approved by a human before publication.