{"id":"CVE-2026-55178","aliases":["EUVD-2026-78775","GHSA-p23g-mvhj-jh3j","PYSEC-2026-3662","PYSEC-2026-3663"],"status":"published","title":"GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data","description":"GeoLens is a self-hosted geospatial data catalog with semantic search, OGC and STAC APIs, and a map builder. Prior to 1.2.3, multiple read and link endpoints authorize only the resource named in the request URL and fail to re-authorize a second caller-influenced dataset reached through a relationship, map layer, VRT source, externalId lookup, or request body. When a public map references a private dataset, anonymous callers can use GET /maps/{id} and GET /maps/{id}/style.json to obtain the private layer's metadata, sampled values, or vector tiles. The style response can expose a replayable HMAC tile URL that is bound to neither a user nor a map. When a public source dataset has a relationship to a private target dataset, anonymous callers can use the dataset relationship APIs to enumerate the relationship and read rows from the private target's backing table. Anonymous callers can also use GET /collections/datasets/items with an externalId dataset UUID to obtain metadata for any private, restricted, or unpublished dataset because that lookup performs no visibility check. Authenticated users with the default editor role can mosaic another user's private raster into an owned VRT and read its pixels, and POST /ai/metadata/{summary,keywords,lineage,quality-statement} accepts a body-controlled dataset_id without a visibility check and returns private metadata and sample values. Pre-existing vrt_source_links also expose unauthorized member metadata and health unless each member is filtered at read time. These paths can disclose vector geometries and attributes, raster pixels, table rows, table names, column schemas, feature counts, extents, source URLs and filenames, contacts, and sampled row values. This issue is fixed in version 1.2.3.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00648,"percentile":0.51336,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-200","CWE-639","CWE-862"],"published":"2026-08-18T18:00:07Z","modified":"2026-10-28T02:30:38Z","fixes":[{"ecosystem":"npm","package":"@geolens/sdk","fixed_in":["1.2.3"],"sources":["ghsa","osv"]},{"ecosystem":"PyPI","package":"geolens-cli","fixed_in":["1.2.3"],"sources":["ghsa","osv"]},{"ecosystem":"PyPI","package":"geolens","fixed_in":["1.2.3"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"@geolens/sdk","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.2.3"}]}]},{"source":"ghsa","ecosystem":"PyPI","package":"geolens-cli","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.2.3"}]}]},{"source":"ghsa","ecosystem":"PyPI","package":"geolens","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.2.3"}]}]},{"source":"osv","ecosystem":"npm","package":"@geolens/sdk","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.2.3"}]}]},{"source":"osv","ecosystem":"PyPI","package":"geolens-cli","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.2.3"}]}],"versions":["1.0.0","1.2.0"]},{"source":"osv","ecosystem":"PyPI","package":"geolens","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.2.3"}]}],"versions":["0.0.0","1.0.0","1.2.0"]},{"source":"osv","ecosystem":"PyPI","package":"geolens","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.2.3"}]}],"versions":["0.0.0","1.0.0","1.2.0"]},{"source":"osv","ecosystem":"PyPI","package":"geolens-cli","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.2.3"}]}],"versions":["1.0.0","1.2.0"]}],"products":[{"vendor":"geolens-io","product":"geolens"}],"references":[{"url":"https://github.com/geolens-io/geolens/security/advisories/GHSA-p23g-mvhj-jh3j","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/geolens-io/geolens/pull/234","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/geolens-io/geolens/pull/235","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/geolens-io/geolens/pull/236","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/geolens-io/geolens/pull/237","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/geolens-io/geolens/pull/238","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/geolens-io/geolens/commit/01bc87da03a5ecd0322c42388f4bfced7cb2ed06","tags":["x_refsource_MISC","fix"]},{"url":"https://github.com/geolens-io/geolens/commit/07dfb1c63ecfc065c0c47b7718ec6ebe97798b1e","tags":["x_refsource_MISC","fix"]},{"url":"https://github.com/geolens-io/geolens/commit/2c031da8e753639ff0e36d47ca05bbb96fbe4a9e","tags":["x_refsource_MISC","fix"]},{"url":"https://github.com/geolens-io/geolens/commit/31a103b96b9fd6ad90308b3e27a581852c4a69bd","tags":["x_refsource_MISC","fix"]},{"url":"https://github.com/geolens-io/geolens/commit/407c068836058fdeca6bb477d39f841316b326a5","tags":["x_refsource_MISC","fix"]},{"url":"https://github.com/geolens-io/geolens/releases/tag/v1.2.3","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/advisories/GHSA-p23g-mvhj-jh3j","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/55xxx/CVE-2026-55178.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-55178","tags":["advisory"]},{"url":"https://github.com/geolens-io/geolens","tags":["package"]},{"url":"https://pypi.org/project/geolens","tags":["package"]},{"url":"https://pypi.org/project/geolens-cli","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-55178","title":"GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data","description":"GeoLens is a self-hosted geospatial data catalog with semantic search, OGC and STAC APIs, and a map builder. Prior to 1.2.3, multiple read and link endpoints authorize only the resource named in the request URL and fail to re-authorize a second caller-influenced dataset reached through a relationship, map layer, VRT source, externalId lookup, or request body. When a public map references a private dataset, anonymous callers can use GET /maps/{id} and GET /maps/{id}/style.json to obtain the private layer's metadata, sampled values, or vector tiles. The style response can expose a replayable HMAC tile URL that is bound to neither a user nor a map. When a public source dataset has a relationship to a private target dataset, anonymous callers can use the dataset relationship APIs to enumerate the relationship and read rows from the private target's backing table. Anonymous callers can also use GET /collections/datasets/items with an externalId dataset UUID to obtain metadata for any private, restricted, or unpublished dataset because that lookup performs no visibility check. Authenticated users with the default editor role can mosaic another user's private raster into an owned VRT and read its pixels, and POST /ai/metadata/{summary,keywords,lineage,quality-statement} accepts a body-controlled dataset_id without a visibility check and returns private metadata and sample values. Pre-existing vrt_source_links also expose unauthorized member metadata and health unless each member is filtered at read time. These paths can disclose vector geometries and attributes, raster pixels, table rows, table names, column schemas, feature counts, extents, source URLs and filenames, contacts, and sampled row values. This issue is fixed in version 1.2.3.","status":"published","published":"2026-09-15T14:58:39.437Z","modified":"2026-09-17T14:44:24.994Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"high","assessor":"cna"}],"cwes":["CWE-200","CWE-639","CWE-862"],"updated_at":"2026-11-02T14:20:12.260247Z"}],"euvd":[{"id":"EUVD-2026-78775","description":"GeoLens is a self-hosted geospatial data catalog with semantic search, OGC and STAC APIs, and a map builder. Prior to 1.2.3, multiple read and link endpoints authorize only the resource named in the request URL and fail to re-authorize a second caller-influenced dataset reached through a relationship, map layer, VRT source, externalId lookup, or request body. When a public map references a private dataset, anonymous callers can use GET /maps/{id} and GET /maps/{id}/style.json to obtain the private layer's metadata, sampled values, or vector tiles. The style response can expose a replayable HMAC tile URL that is bound to neither a user nor a map. When a public source dataset has a relationship to a private target dataset, anonymous callers can use the dataset relationship APIs to enumerate the relationship and read rows from the private target's backing table. Anonymous callers can also use GET /collections/datasets/items with an externalId dataset UUID to obtain metadata for any private, restricted, or unpublished dataset because that lookup performs no visibility check. Authenticated users with the default editor role can mosaic another user's private raster into an owned VRT and read its pixels, and POST /ai/metadata/{summary,keywords,lineage,quality-statement} accepts a body-controlled dataset_id without a visibility check and returns private metadata and sample values. Pre-existing vrt_source_links also expose unauthorized member metadata and health unless each member is filtered at read time. These paths can disclose vector geometries and attributes, raster pixels, table rows, table names, column schemas, feature counts, extents, source URLs and filenames, contacts, and sampled row values. This issue is fixed in version 1.2.3.","status":"published","published":"2026-09-15T14:58:39Z","modified":"2026-09-17T14:44:24Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"high"}],"updated_at":"2026-11-02T17:28:12.076337Z"}],"ghsa":[{"id":"GHSA-p23g-mvhj-jh3j","title":"GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data","description":"### Summary\n\nMultiple GeoLens read/link endpoints authorized only the resource named in the\nrequest URL (a map, a VRT, a source dataset, an AI request) and failed to\nre-authorize a **second, caller-influenced dataset** that the request reached\nthrough a relationship, layer reference, mosaic source, or request body. This\n\"authorize the URL resource, read a *different* dataset un-re-authorized\"\npattern let callers read data from datasets they have no access to.\n\nThe most severe instances require **no authentication at all** (anonymous,\nnetwork-only). Others require only the **default `editor` role** that any\nself-service signup / upload user receives.\n\nAll issues are fixed in **1.2.3**. There is no complete configuration\nworkaround — upgrading is the only full remediation.\n\n### Impact\n\nDepending on the endpoint, an attacker can read, for datasets they cannot\notherwise access:\n\n- the dataset's **vector tile data** (actual feature geometries/attributes),\n- the dataset's **raster pixels**,\n- backing-table **rows**,\n- and **metadata** — table name, column schema, feature count, extent, source\n  URL/filename, contacts, and **sampled row values**.\n\n### Affected versions\n\nAll versions **prior to 1.2.3** (includes the published 1.0.0, 1.2.0, and\n1.2.2 releases and their PyPI/npm/GHCR artifacts). Fixed in **1.2.3**.\n\n### Findings\n\n**1. Anonymous metadata + private vector-tile disclosure via public maps (PR #235)**\n`GET /maps/{id}` and `GET /maps/{id}/style.json` authorized the map but not\neach layer's backing dataset. A public map that references a private dataset\nleaked that dataset's table name, column schema, feature count, extent, and\nsampled values to anonymous callers. `style.json` additionally returned a\nvector-tile URL carrying an HMAC signature bound to **neither user nor map**,\nwhich the tile endpoint accepts for non-public datasets with no user check —\nso the signature is **replayable** to read the private dataset's actual vector\ntiles. *(Anonymous · High)*\n\n**2. Anonymous private-row disclosure via dataset relationships (PR #234)**\nThe dataset FK-relationship APIs authorized only the source dataset from the\nURL, never the relationship target. A public dataset with a relationship to a\nprivate dataset let an anonymous caller enumerate the relationship (obtaining\nthe private target's id/title and the relationship id) and then call the\nrelated-record endpoint to read **rows from the private target's backing\ntable**. *(Anonymous · High)*\n\n**3. Anonymous metadata disclosure via OGC `externalId` lookup (PR #236)**\n`GET /collections/datasets/items?externalId=\u003cuuid\u003e` resolved the dataset by id\nand returned the full OGC catalog record (title, summary, bbox, keywords,\ncontacts, distributions, source org) with **no visibility check** — the user\nwas never threaded into the lookup. An anonymous caller could read any\nprivate, restricted, or unpublished dataset's metadata by UUID. *(Anonymous ·\nHigh)*\n\n**4. Cross-tenant raster pixel disclosure via VRT mosaics — SEC-C (PR #237)**\nAn authenticated user with the default `editor` upload permission could mosaic\nanother user's **private raster** into a VRT they own, then read the victim's\n**pixels** back through raster tile / quicklook / COG endpoints that authorize\nonly the attacker-owned VRT. VRT member pixels are compiled into one served\nasset and cannot be filtered at read time, so the fix authorizes every source\ndataset at write/link time. *(Authenticated `editor` · High)*\n\n**5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints — SEC-D (PR #238)**\nThe `POST /ai/metadata/{summary,keywords,lineage,quality-statement}` endpoints\nwere gated only by the `use_ai_chat` permission (held by the default `editor`\nrole). The attacker-controlled `dataset_id` in the request body flowed into the\nLLM prompt context with no visibility filter, rendering **any** dataset's\ntitle, summary, source URL, filename, column schema, and **sample values** into\nthe response. *(Authenticated `editor` · High)*\n\n**6. Residual VRT member disclosure for legacy links — SEC-E (PR #237)**\nLink-time authorization (finding 4) does not re-authorize pre-existing\n`vrt_source_links`, so legacy or authorization-drift links still leaked member\nmetadata and health via the VRT source-listing/status endpoints until a\nper-member read filter was added. *(Medium)*\n\n### Patches\n\nFixed in **1.2.3** by, in order:\n\n- `31a103b9` — fix(catalog): authorize relationship targets in related-record endpoints (#234)\n- `01bc87da` — fix(maps): re-authorize each layer's dataset on anonymous map read endpoints (#235)\n- `407c0688` — fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)\n- `2c031da8` — fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)\n- `07dfb1c6` — fix(ai): authorize the requested dataset on AI metadata endpoints (#238)\n\nThe fixes follow the codebase's established per-dataset re-authorization pattern\n(`can_access_dataset` / `check_dataset_access_or_anonymous`), filtering at read\ntime and authorizing cross-dataset references at link/write time.\n\n### Workarounds\n\nThere is **no complete configuration workaround**; the anonymous findings\nrequire only network access to the API. Operators who cannot upgrade\nimmediately should restrict network exposure of the API and avoid co-locating\nprivate datasets with public maps/relationships, but **upgrading to 1.2.3 is\nthe only full remediation**.\n\n### Remediation\n\nUpgrade to GeoLens **1.2.3**:\n- Container images: `ghcr.io/geolens-io/geolens-api:1.2.3` (+ worker/frontend)\n- Python SDK: `geolens==1.2.3` · CLI: `geolens-cli==1.2.3` · npm: `@geolens/sdk@1.2.3`","status":"published","published":"2026-08-18T18:00:07Z","modified":"2026-08-18T18:00:09Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"high"}],"cwes":["CWE-200","CWE-639","CWE-862"],"updated_at":"2026-11-02T14:41:03.602876Z"}],"nvd":[{"id":"CVE-2026-55178","description":"GeoLens is a self-hosted geospatial data catalog with semantic search, OGC and STAC APIs, and a map builder. Prior to 1.2.3, multiple read and link endpoints authorize only the resource named in the request URL and fail to re-authorize a second caller-influenced dataset reached through a relationship, map layer, VRT source, externalId lookup, or request body. When a public map references a private dataset, anonymous callers can use GET /maps/{id} and GET /maps/{id}/style.json to obtain the private layer's metadata, sampled values, or vector tiles. The style response can expose a replayable HMAC tile URL that is bound to neither a user nor a map. When a public source dataset has a relationship to a private target dataset, anonymous callers can use the dataset relationship APIs to enumerate the relationship and read rows from the private target's backing table. Anonymous callers can also use GET /collections/datasets/items with an externalId dataset UUID to obtain metadata for any private, restricted, or unpublished dataset because that lookup performs no visibility check. Authenticated users with the default editor role can mosaic another user's private raster into an owned VRT and read its pixels, and POST /ai/metadata/{summary,keywords,lineage,quality-statement} accepts a body-controlled dataset_id without a visibility check and returns private metadata and sample values. Pre-existing vrt_source_links also expose unauthorized member metadata and health unless each member is filtered at read time. These paths can disclose vector geometries and attributes, raster pixels, table rows, table names, column schemas, feature counts, extents, source URLs and filenames, contacts, and sampled row values. This issue is fixed in version 1.2.3.","status":"published","published":"2026-09-15T15:17:18.747Z","modified":"2026-09-30T17:51:56.193Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"high","assessor":"secondary"}],"cwes":["CWE-200","CWE-639","CWE-862"],"updated_at":"2026-11-02T14:12:47.668237Z"}],"osv":[{"id":"CVE-2026-55178","title":"GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data","description":"GeoLens is a self-hosted geospatial data catalog with semantic search, OGC and STAC APIs, and a map builder. Prior to 1.2.3, multiple read and link endpoints authorize only the resource named in the request URL and fail to re-authorize a second caller-influenced dataset reached through a relationship, map layer, VRT source, externalId lookup, or request body. When a public map references a private dataset, anonymous callers can use GET /maps/{id} and GET /maps/{id}/style.json to obtain the private layer's metadata, sampled values, or vector tiles. The style response can expose a replayable HMAC tile URL that is bound to neither a user nor a map. When a public source dataset has a relationship to a private target dataset, anonymous callers can use the dataset relationship APIs to enumerate the relationship and read rows from the private target's backing table. Anonymous callers can also use GET /collections/datasets/items with an externalId dataset UUID to obtain metadata for any private, restricted, or unpublished dataset because that lookup performs no visibility check. Authenticated users with the default editor role can mosaic another user's private raster into an owned VRT and read its pixels, and POST /ai/metadata/{summary,keywords,lineage,quality-statement} accepts a body-controlled dataset_id without a visibility check and returns private metadata and sample values. Pre-existing vrt_source_links also expose unauthorized member metadata and health unless each member is filtered at read time. These paths can disclose vector geometries and attributes, raster pixels, table rows, table names, column schemas, feature counts, extents, source URLs and filenames, contacts, and sampled row values. This issue is fixed in version 1.2.3.","status":"published","published":"2026-09-15T14:58:39.437Z","modified":"2026-10-28T02:30:38.569862315Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"high"}],"cwes":["CWE-200","CWE-639","CWE-862"],"updated_at":"2026-11-02T15:45:11.22012Z"},{"id":"GHSA-p23g-mvhj-jh3j","title":"GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data","description":"### Summary\n\nMultiple GeoLens read/link endpoints authorized only the resource named in the\nrequest URL (a map, a VRT, a source dataset, an AI request) and failed to\nre-authorize a **second, caller-influenced dataset** that the request reached\nthrough a relationship, layer reference, mosaic source, or request body. This\n\"authorize the URL resource, read a *different* dataset un-re-authorized\"\npattern let callers read data from datasets they have no access to.\n\nThe most severe instances require **no authentication at all** (anonymous,\nnetwork-only). Others require only the **default `editor` role** that any\nself-service signup / upload user receives.\n\nAll issues are fixed in **1.2.3**. There is no complete configuration\nworkaround — upgrading is the only full remediation.\n\n### Impact\n\nDepending on the endpoint, an attacker can read, for datasets they cannot\notherwise access:\n\n- the dataset's **vector tile data** (actual feature geometries/attributes),\n- the dataset's **raster pixels**,\n- backing-table **rows**,\n- and **metadata** — table name, column schema, feature count, extent, source\n  URL/filename, contacts, and **sampled row values**.\n\n### Affected versions\n\nAll versions **prior to 1.2.3** (includes the published 1.0.0, 1.2.0, and\n1.2.2 releases and their PyPI/npm/GHCR artifacts). Fixed in **1.2.3**.\n\n### Findings\n\n**1. Anonymous metadata + private vector-tile disclosure via public maps (PR #235)**\n`GET /maps/{id}` and `GET /maps/{id}/style.json` authorized the map but not\neach layer's backing dataset. A public map that references a private dataset\nleaked that dataset's table name, column schema, feature count, extent, and\nsampled values to anonymous callers. `style.json` additionally returned a\nvector-tile URL carrying an HMAC signature bound to **neither user nor map**,\nwhich the tile endpoint accepts for non-public datasets with no user check —\nso the signature is **replayable** to read the private dataset's actual vector\ntiles. *(Anonymous · High)*\n\n**2. Anonymous private-row disclosure via dataset relationships (PR #234)**\nThe dataset FK-relationship APIs authorized only the source dataset from the\nURL, never the relationship target. A public dataset with a relationship to a\nprivate dataset let an anonymous caller enumerate the relationship (obtaining\nthe private target's id/title and the relationship id) and then call the\nrelated-record endpoint to read **rows from the private target's backing\ntable**. *(Anonymous · High)*\n\n**3. Anonymous metadata disclosure via OGC `externalId` lookup (PR #236)**\n`GET /collections/datasets/items?externalId=\u003cuuid\u003e` resolved the dataset by id\nand returned the full OGC catalog record (title, summary, bbox, keywords,\ncontacts, distributions, source org) with **no visibility check** — the user\nwas never threaded into the lookup. An anonymous caller could read any\nprivate, restricted, or unpublished dataset's metadata by UUID. *(Anonymous ·\nHigh)*\n\n**4. Cross-tenant raster pixel disclosure via VRT mosaics — SEC-C (PR #237)**\nAn authenticated user with the default `editor` upload permission could mosaic\nanother user's **private raster** into a VRT they own, then read the victim's\n**pixels** back through raster tile / quicklook / COG endpoints that authorize\nonly the attacker-owned VRT. VRT member pixels are compiled into one served\nasset and cannot be filtered at read time, so the fix authorizes every source\ndataset at write/link time. *(Authenticated `editor` · High)*\n\n**5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints — SEC-D (PR #238)**\nThe `POST /ai/metadata/{summary,keywords,lineage,quality-statement}` endpoints\nwere gated only by the `use_ai_chat` permission (held by the default `editor`\nrole). The attacker-controlled `dataset_id` in the request body flowed into the\nLLM prompt context with no visibility filter, rendering **any** dataset's\ntitle, summary, source URL, filename, column schema, and **sample values** into\nthe response. *(Authenticated `editor` · High)*\n\n**6. Residual VRT member disclosure for legacy links — SEC-E (PR #237)**\nLink-time authorization (finding 4) does not re-authorize pre-existing\n`vrt_source_links`, so legacy or authorization-drift links still leaked member\nmetadata and health via the VRT source-listing/status endpoints until a\nper-member read filter was added. *(Medium)*\n\n### Patches\n\nFixed in **1.2.3** by, in order:\n\n- `31a103b9` — fix(catalog): authorize relationship targets in related-record endpoints (#234)\n- `01bc87da` — fix(maps): re-authorize each layer's dataset on anonymous map read endpoints (#235)\n- `407c0688` — fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)\n- `2c031da8` — fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)\n- `07dfb1c6` — fix(ai): authorize the requested dataset on AI metadata endpoints (#238)\n\nThe fixes follow the codebase's established per-dataset re-authorization pattern\n(`can_access_dataset` / `check_dataset_access_or_anonymous`), filtering at read\ntime and authorizing cross-dataset references at link/write time.\n\n### Workarounds\n\nThere is **no complete configuration workaround**; the anonymous findings\nrequire only network access to the API. Operators who cannot upgrade\nimmediately should restrict network exposure of the API and avoid co-locating\nprivate datasets with public maps/relationships, but **upgrading to 1.2.3 is\nthe only full remediation**.\n\n### Remediation\n\nUpgrade to GeoLens **1.2.3**:\n- Container images: `ghcr.io/geolens-io/geolens-api:1.2.3` (+ worker/frontend)\n- Python SDK: `geolens==1.2.3` · CLI: `geolens-cli==1.2.3` · npm: `@geolens/sdk@1.2.3`","status":"published","published":"2026-08-18T18:00:07Z","modified":"2026-08-19T12:55:45.829355044Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"high"}],"cwes":["CWE-200","CWE-639","CWE-862"],"updated_at":"2026-11-02T15:46:52.534897Z"},{"id":"PYSEC-2026-3662","title":"GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data","description":"### Summary\n\nMultiple GeoLens read/link endpoints authorized only the resource named in the\nrequest URL (a map, a VRT, a source dataset, an AI request) and failed to\nre-authorize a **second, caller-influenced dataset** that the request reached\nthrough a relationship, layer reference, mosaic source, or request body. This\n\"authorize the URL resource, read a *different* dataset un-re-authorized\"\npattern let callers read data from datasets they have no access to.\n\nThe most severe instances require **no authentication at all** (anonymous,\nnetwork-only). Others require only the **default `editor` role** that any\nself-service signup / upload user receives.\n\nAll issues are fixed in **1.2.3**. There is no complete configuration\nworkaround — upgrading is the only full remediation.\n\n### Impact\n\nDepending on the endpoint, an attacker can read, for datasets they cannot\notherwise access:\n\n- the dataset's **vector tile data** (actual feature geometries/attributes),\n- the dataset's **raster pixels**,\n- backing-table **rows**,\n- and **metadata** — table name, column schema, feature count, extent, source\n  URL/filename, contacts, and **sampled row values**.\n\n### Affected versions\n\nAll versions **prior to 1.2.3** (includes the published 1.0.0, 1.2.0, and\n1.2.2 releases and their PyPI/npm/GHCR artifacts). Fixed in **1.2.3**.\n\n### Findings\n\n**1. Anonymous metadata + private vector-tile disclosure via public maps (PR #235)**\n`GET /maps/{id}` and `GET /maps/{id}/style.json` authorized the map but not\neach layer's backing dataset. A public map that references a private dataset\nleaked that dataset's table name, column schema, feature count, extent, and\nsampled values to anonymous callers. `style.json` additionally returned a\nvector-tile URL carrying an HMAC signature bound to **neither user nor map**,\nwhich the tile endpoint accepts for non-public datasets with no user check —\nso the signature is **replayable** to read the private dataset's actual vector\ntiles. *(Anonymous · High)*\n\n**2. Anonymous private-row disclosure via dataset relationships (PR #234)**\nThe dataset FK-relationship APIs authorized only the source dataset from the\nURL, never the relationship target. A public dataset with a relationship to a\nprivate dataset let an anonymous caller enumerate the relationship (obtaining\nthe private target's id/title and the relationship id) and then call the\nrelated-record endpoint to read **rows from the private target's backing\ntable**. *(Anonymous · High)*\n\n**3. Anonymous metadata disclosure via OGC `externalId` lookup (PR #236)**\n`GET /collections/datasets/items?externalId=\u003cuuid\u003e` resolved the dataset by id\nand returned the full OGC catalog record (title, summary, bbox, keywords,\ncontacts, distributions, source org) with **no visibility check** — the user\nwas never threaded into the lookup. An anonymous caller could read any\nprivate, restricted, or unpublished dataset's metadata by UUID. *(Anonymous ·\nHigh)*\n\n**4. Cross-tenant raster pixel disclosure via VRT mosaics — SEC-C (PR #237)**\nAn authenticated user with the default `editor` upload permission could mosaic\nanother user's **private raster** into a VRT they own, then read the victim's\n**pixels** back through raster tile / quicklook / COG endpoints that authorize\nonly the attacker-owned VRT. VRT member pixels are compiled into one served\nasset and cannot be filtered at read time, so the fix authorizes every source\ndataset at write/link time. *(Authenticated `editor` · High)*\n\n**5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints — SEC-D (PR #238)**\nThe `POST /ai/metadata/{summary,keywords,lineage,quality-statement}` endpoints\nwere gated only by the `use_ai_chat` permission (held by the default `editor`\nrole). The attacker-controlled `dataset_id` in the request body flowed into the\nLLM prompt context with no visibility filter, rendering **any** dataset's\ntitle, summary, source URL, filename, column schema, and **sample values** into\nthe response. *(Authenticated `editor` · High)*\n\n**6. Residual VRT member disclosure for legacy links — SEC-E (PR #237)**\nLink-time authorization (finding 4) does not re-authorize pre-existing\n`vrt_source_links`, so legacy or authorization-drift links still leaked member\nmetadata and health via the VRT source-listing/status endpoints until a\nper-member read filter was added. *(Medium)*\n\n### Patches\n\nFixed in **1.2.3** by, in order:\n\n- `31a103b9` — fix(catalog): authorize relationship targets in related-record endpoints (#234)\n- `01bc87da` — fix(maps): re-authorize each layer's dataset on anonymous map read endpoints (#235)\n- `407c0688` — fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)\n- `2c031da8` — fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)\n- `07dfb1c6` — fix(ai): authorize the requested dataset on AI metadata endpoints (#238)\n\nThe fixes follow the codebase's established per-dataset re-authorization pattern\n(`can_access_dataset` / `check_dataset_access_or_anonymous`), filtering at read\ntime and authorizing cross-dataset references at link/write time.\n\n### Workarounds\n\nThere is **no complete configuration workaround**; the anonymous findings\nrequire only network access to the API. Operators who cannot upgrade\nimmediately should restrict network exposure of the API and avoid co-locating\nprivate datasets with public maps/relationships, but **upgrading to 1.2.3 is\nthe only full remediation**.\n\n### Remediation\n\nUpgrade to GeoLens **1.2.3**:\n- Container images: `ghcr.io/geolens-io/geolens-api:1.2.3` (+ worker/frontend)\n- Python SDK: `geolens==1.2.3` · CLI: `geolens-cli==1.2.3` · npm: `@geolens/sdk@1.2.3`","status":"published","published":"2026-08-19T11:56:27.504188Z","modified":"2026-08-19T12:55:45.829355044Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"high"}],"updated_at":"2026-11-02T15:52:56.847083Z"},{"id":"PYSEC-2026-3663","title":"GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data","description":"### Summary\n\nMultiple GeoLens read/link endpoints authorized only the resource named in the\nrequest URL (a map, a VRT, a source dataset, an AI request) and failed to\nre-authorize a **second, caller-influenced dataset** that the request reached\nthrough a relationship, layer reference, mosaic source, or request body. This\n\"authorize the URL resource, read a *different* dataset un-re-authorized\"\npattern let callers read data from datasets they have no access to.\n\nThe most severe instances require **no authentication at all** (anonymous,\nnetwork-only). Others require only the **default `editor` role** that any\nself-service signup / upload user receives.\n\nAll issues are fixed in **1.2.3**. There is no complete configuration\nworkaround — upgrading is the only full remediation.\n\n### Impact\n\nDepending on the endpoint, an attacker can read, for datasets they cannot\notherwise access:\n\n- the dataset's **vector tile data** (actual feature geometries/attributes),\n- the dataset's **raster pixels**,\n- backing-table **rows**,\n- and **metadata** — table name, column schema, feature count, extent, source\n  URL/filename, contacts, and **sampled row values**.\n\n### Affected versions\n\nAll versions **prior to 1.2.3** (includes the published 1.0.0, 1.2.0, and\n1.2.2 releases and their PyPI/npm/GHCR artifacts). Fixed in **1.2.3**.\n\n### Findings\n\n**1. Anonymous metadata + private vector-tile disclosure via public maps (PR #235)**\n`GET /maps/{id}` and `GET /maps/{id}/style.json` authorized the map but not\neach layer's backing dataset. A public map that references a private dataset\nleaked that dataset's table name, column schema, feature count, extent, and\nsampled values to anonymous callers. `style.json` additionally returned a\nvector-tile URL carrying an HMAC signature bound to **neither user nor map**,\nwhich the tile endpoint accepts for non-public datasets with no user check —\nso the signature is **replayable** to read the private dataset's actual vector\ntiles. *(Anonymous · High)*\n\n**2. Anonymous private-row disclosure via dataset relationships (PR #234)**\nThe dataset FK-relationship APIs authorized only the source dataset from the\nURL, never the relationship target. A public dataset with a relationship to a\nprivate dataset let an anonymous caller enumerate the relationship (obtaining\nthe private target's id/title and the relationship id) and then call the\nrelated-record endpoint to read **rows from the private target's backing\ntable**. *(Anonymous · High)*\n\n**3. Anonymous metadata disclosure via OGC `externalId` lookup (PR #236)**\n`GET /collections/datasets/items?externalId=\u003cuuid\u003e` resolved the dataset by id\nand returned the full OGC catalog record (title, summary, bbox, keywords,\ncontacts, distributions, source org) with **no visibility check** — the user\nwas never threaded into the lookup. An anonymous caller could read any\nprivate, restricted, or unpublished dataset's metadata by UUID. *(Anonymous ·\nHigh)*\n\n**4. Cross-tenant raster pixel disclosure via VRT mosaics — SEC-C (PR #237)**\nAn authenticated user with the default `editor` upload permission could mosaic\nanother user's **private raster** into a VRT they own, then read the victim's\n**pixels** back through raster tile / quicklook / COG endpoints that authorize\nonly the attacker-owned VRT. VRT member pixels are compiled into one served\nasset and cannot be filtered at read time, so the fix authorizes every source\ndataset at write/link time. *(Authenticated `editor` · High)*\n\n**5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints — SEC-D (PR #238)**\nThe `POST /ai/metadata/{summary,keywords,lineage,quality-statement}` endpoints\nwere gated only by the `use_ai_chat` permission (held by the default `editor`\nrole). The attacker-controlled `dataset_id` in the request body flowed into the\nLLM prompt context with no visibility filter, rendering **any** dataset's\ntitle, summary, source URL, filename, column schema, and **sample values** into\nthe response. *(Authenticated `editor` · High)*\n\n**6. Residual VRT member disclosure for legacy links — SEC-E (PR #237)**\nLink-time authorization (finding 4) does not re-authorize pre-existing\n`vrt_source_links`, so legacy or authorization-drift links still leaked member\nmetadata and health via the VRT source-listing/status endpoints until a\nper-member read filter was added. *(Medium)*\n\n### Patches\n\nFixed in **1.2.3** by, in order:\n\n- `31a103b9` — fix(catalog): authorize relationship targets in related-record endpoints (#234)\n- `01bc87da` — fix(maps): re-authorize each layer's dataset on anonymous map read endpoints (#235)\n- `407c0688` — fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)\n- `2c031da8` — fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)\n- `07dfb1c6` — fix(ai): authorize the requested dataset on AI metadata endpoints (#238)\n\nThe fixes follow the codebase's established per-dataset re-authorization pattern\n(`can_access_dataset` / `check_dataset_access_or_anonymous`), filtering at read\ntime and authorizing cross-dataset references at link/write time.\n\n### Workarounds\n\nThere is **no complete configuration workaround**; the anonymous findings\nrequire only network access to the API. Operators who cannot upgrade\nimmediately should restrict network exposure of the API and avoid co-locating\nprivate datasets with public maps/relationships, but **upgrading to 1.2.3 is\nthe only full remediation**.\n\n### Remediation\n\nUpgrade to GeoLens **1.2.3**:\n- Container images: `ghcr.io/geolens-io/geolens-api:1.2.3` (+ worker/frontend)\n- Python SDK: `geolens==1.2.3` · CLI: `geolens-cli==1.2.3` · npm: `@geolens/sdk@1.2.3`","status":"published","published":"2026-08-19T11:56:27.453934Z","modified":"2026-08-19T12:55:45.829355044Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"high"}],"updated_at":"2026-11-02T15:52:56.847083Z"}]}}
