Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.
This repository was archived by the owner on May 29, 2026. It is now read-only.

[HIGH] H1: Cross-tenant data leakage in ZGW reads — no organisation filter for non-superuser consumers, getTenantStatus fails open #643

Description

@rubenvdlinde

Severity: HIGH

Location: lib/Service/ZgwService.php:901-904

Description:
searchObjectsPaginated is called with _multitenancy: false throughout handleIndex and handleShow. Additionally, getTenantStatus fails open on exception (returns a permissive default rather than throwing). The result is that non-superuser consumers can read records belonging to other tenants/organisations when the tenant resolution encounters any error condition.

In a multi-municipality deployment (the typical procest scenario) this means one municipality's medewerkers can read another municipality's zaak records, including BSN, names, and case history.

Scenario:

  1. Municipality A and Municipality B both use the same procest instance.
  2. A medewerker from Municipality A's consumer makes a GET /api/zrc/zaken request.
  3. getTenantStatus throws an exception (e.g., a transient DB error or misconfigured tenant config).
  4. The fail-open handler returns a permissive default.
  5. searchObjectsPaginated runs with no tenant filter — Municipality B's zaken are included in the response.

Suggested fix:

  • Pass an organisation = <consumer.tenant> filter to searchObjectsPaginated for all non-superuser consumers.
  • Change getTenantStatus to fail-closed: on exception, throw or return a state that causes a 503 rather than proceeding without a tenant constraint.
  • Add an integration test that verifies cross-tenant records are never returned to a non-superuser consumer.

Source: deep team-reviewer pass 2026-05-27

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions