Skip to content

security(spp_api_v2_gis): OGC features numberMatched / report record_count / export leak unsuppressed beneficiary counts [Severity: Medium] #373

Description

@gonzalesedwin1123

Follow-up from the adversarial review of PR #366 (GIS count k-anonymity). PR #366 suppresses the spatial-query / proximity / batch count paths named in the original report, but the review found the same class of count/presence leak in adjacent GIS endpoints that #366 does not touch. Filing so the module's count surfaces get consistent k-anonymity.

Findings (file:line on origin/19.0)

  1. OGC Features numberMatched/numberReturnedspp_api_v2_gis/services/ogc_service.py:305-306 returns numberMatched = layers_service.get_feature_count(...) and numberReturned = len(features) for GET /gis/ogc/collections/{id}/items with an attacker-controlled bbox. get_feature_count is a raw search_count (services/layers_service.py:377,406) with no k-anonymity. For a data layer over a person-like model this is a per-bbox count oracle at arbitrary granularity — and the endpoint also returns the actual feature geometries and properties (individual records, _fetch_layer_features layers_service.py:317-380).
  2. Report feature record_count_get_report_feature_by_id / report items return "record_count": data.record_count per area plus raw_value/display_value (services/layers_service.py:~470-482) with no suppression; a small admin area with record_count=1 leaks single-beneficiary presence via the OGC items list and single-feature endpoint.
  3. Exportexport_service serializes the same report/data-layer GeoJSON (services/export_service.py:95,113), so GeoPackage/ZIP exports carry the same unsuppressed per-area record_count/values and any data-layer records.

Notes

  • The raw data-layer record exposure may be a pre-existing admin-configuration design choice (layers configured over person models); worth a design decision on whether GIS data layers should ever expose individual records to gis:read.
  • The unsuppressed report record_count and OGC numberMatched under an attacker-chosen bbox are the clearest count/presence oracles and should get the same k-anonymity treatment PR security(gis): apply k-anonymity suppression to spatial query beneficiary counts #366 applies to spatial queries (reuse spp.analytics.service.get_effective_k_threshold() + a canonical-suppression helper).
  • Cleared as safe: statistics router total_count = number of indicator definitions; geofence counts = the caller's own saved AOIs.

Distinct from #367 (batch differencing) and #368 (proximity-beyond differencing). Source: adversarial review of PR #366.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions