Skip to content

CMS, identity, and permission-boundary batch

Source: GitHub Security Advisories updated 2026-05-13.

This batch is durable because the advisories repeat the same failure mode across CMS, SaaS-auth, and admin surfaces: UI-visible roles, object IDs, forwarded headers, and “already authenticated” checks were treated as sufficient authorization. The result is privilege escalation, content overwrite, API data disclosure, account takeover, and destructive importer access.

Advisories covered

Operator triage

  1. Prioritize exposed admin panels, hosted CMS, VPN/OIDC gateways, and public dashboards before internal-only instances.
  2. Upgrade affected packages, then invalidate sessions/tokens where auth, role, reset-link, or SAML/OIDC identity state may have been bypassed.
  3. Search access logs for Grav plugin ZIP/direct-install actions, FormFlash writes, /importer, AzuraCast reset requests with unusual Host/X-Forwarded-Host values, Wagtail API enumeration, and Clerk endpoints that combine org/billing/reverification guards.
  4. For destructive bugs, verify backups before upgrade and preserve evidence before cleanup.

Durable controls

  • Enforce authorization server-side on every mutating and sensitive-read endpoint; UI role state is only a hint.
  • Treat Host and proxy headers as untrusted unless set by a trusted reverse proxy and validated against a configured external URL.
  • File upload and plugin install paths need allowlisted extensions, archive root checks, symlink rejection, and execution disabled unless explicitly intended.
  • Identity providers should fail closed: a deny result, missing group, failed reverification, or unrecognized SAML assertion must stop the request, not continue with partial success.

August 7 follow-up: fail-closed webhook and attachment-object matrices

Missing webhook proof must not mean anonymous success

Use only a disposable Grav instance with the separate scheduler-webhook plugin installed and synthetic jobs whose handlers increment an in-memory counter. Test webhook disabled/enabled against token absent, empty, wrong, and matching, and vary no job, a known canary job, and an unknown job. Record route match, effective configuration, supplied proof state, selected job IDs, and the patched scheduler sink.

A bounded positive is webhook enabled + token absent -> anonymous request reaches the canary job sink, while a wrong token is denied when a token exists. Do not configure shell jobs, trigger backups or maintenance, or call this attacker-chosen RCE: the caller chooses timing and possibly an existing job identifier, while the operator chose the job body. Stock Grav without the plugin, or with the webhook disabled, is not exposed by this route.

Attachment IDs need parent-project authorization at the download sink

Create two TestLink projects and two synthetic users: one member of project A and one guest or non-member for project B. Upload marker-only text attachments, capture their IDs through each user's legitimate UI, then replay the download handler with same-project ID, other-project ID, nonexistent ID, malformed ID, and a role lacking attachment access. Patch or proxy the final file response so it returns only marker identity and byte count.

The decisive result is authenticated project-A principal + project-B attachment ID -> project-B marker reaches the response recorder without project-B membership. Do not enumerate production IDs or retrieve test plans, evidence, requirements, or user uploads. State whether IDs are sequential as a recon aid separately from the missing parent-object check; predictability is not the authorization flaw.