Find a vulnerability
Search criteria
Related vulnerabilities
GHSA-P23G-MVHJ-JH3J
Vulnerability from github – Published: 2026-08-18 18:00 – Updated: 2026-08-18 18:00Summary
Multiple GeoLens read/link endpoints authorized only the resource named in the request URL (a map, a VRT, a source dataset, an AI request) and failed to re-authorize a second, caller-influenced dataset that the request reached through a relationship, layer reference, mosaic source, or request body. This "authorize the URL resource, read a different dataset un-re-authorized" pattern let callers read data from datasets they have no access to.
The most severe instances require no authentication at all (anonymous,
network-only). Others require only the default editor role that any
self-service signup / upload user receives.
All issues are fixed in 1.2.3. There is no complete configuration workaround — upgrading is the only full remediation.
Impact
Depending on the endpoint, an attacker can read, for datasets they cannot otherwise access:
- the dataset's vector tile data (actual feature geometries/attributes),
- the dataset's raster pixels,
- backing-table rows,
- and metadata — table name, column schema, feature count, extent, source URL/filename, contacts, and sampled row values.
Affected versions
All versions prior to 1.2.3 (includes the published 1.0.0, 1.2.0, and 1.2.2 releases and their PyPI/npm/GHCR artifacts). Fixed in 1.2.3.
Findings
1. Anonymous metadata + private vector-tile disclosure via public maps (PR #235)
GET /maps/{id} and GET /maps/{id}/style.json authorized the map but not
each layer's backing dataset. A public map that references a private dataset
leaked that dataset's table name, column schema, feature count, extent, and
sampled values to anonymous callers. style.json additionally returned a
vector-tile URL carrying an HMAC signature bound to neither user nor map,
which the tile endpoint accepts for non-public datasets with no user check —
so the signature is replayable to read the private dataset's actual vector
tiles. (Anonymous · High)
2. Anonymous private-row disclosure via dataset relationships (PR #234) The dataset FK-relationship APIs authorized only the source dataset from the URL, never the relationship target. A public dataset with a relationship to a private dataset let an anonymous caller enumerate the relationship (obtaining the private target's id/title and the relationship id) and then call the related-record endpoint to read rows from the private target's backing table. (Anonymous · High)
3. Anonymous metadata disclosure via OGC externalId lookup (PR #236)
GET /collections/datasets/items?externalId=<uuid> resolved the dataset by id
and returned the full OGC catalog record (title, summary, bbox, keywords,
contacts, distributions, source org) with no visibility check — the user
was never threaded into the lookup. An anonymous caller could read any
private, restricted, or unpublished dataset's metadata by UUID. (Anonymous ·
High)
4. Cross-tenant raster pixel disclosure via VRT mosaics — SEC-C (PR #237)
An authenticated user with the default editor upload permission could mosaic
another user's private raster into a VRT they own, then read the victim's
pixels back through raster tile / quicklook / COG endpoints that authorize
only the attacker-owned VRT. VRT member pixels are compiled into one served
asset and cannot be filtered at read time, so the fix authorizes every source
dataset at write/link time. (Authenticated editor · High)
5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints — SEC-D (PR #238)
The POST /ai/metadata/{summary,keywords,lineage,quality-statement} endpoints
were gated only by the use_ai_chat permission (held by the default editor
role). The attacker-controlled dataset_id in the request body flowed into the
LLM prompt context with no visibility filter, rendering any dataset's
title, summary, source URL, filename, column schema, and sample values into
the response. (Authenticated editor · High)
6. Residual VRT member disclosure for legacy links — SEC-E (PR #237)
Link-time authorization (finding 4) does not re-authorize pre-existing
vrt_source_links, so legacy or authorization-drift links still leaked member
metadata and health via the VRT source-listing/status endpoints until a
per-member read filter was added. (Medium)
Patches
Fixed in 1.2.3 by, in order:
31a103b9— fix(catalog): authorize relationship targets in related-record endpoints (#234)01bc87da— fix(maps): re-authorize each layer's dataset on anonymous map read endpoints (#235)407c0688— fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)2c031da8— fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)07dfb1c6— fix(ai): authorize the requested dataset on AI metadata endpoints (#238)
The fixes follow the codebase's established per-dataset re-authorization pattern
(can_access_dataset / check_dataset_access_or_anonymous), filtering at read
time and authorizing cross-dataset references at link/write time.
Workarounds
There is no complete configuration workaround; the anonymous findings require only network access to the API. Operators who cannot upgrade immediately should restrict network exposure of the API and avoid co-locating private datasets with public maps/relationships, but upgrading to 1.2.3 is the only full remediation.
Remediation
Upgrade to GeoLens 1.2.3:
- Container images: ghcr.io/geolens-io/geolens-api:1.2.3 (+ worker/frontend)
- Python SDK: geolens==1.2.3 · CLI: geolens-cli==1.2.3 · npm: @geolens/sdk@1.2.3
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "@geolens/sdk"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.2.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "geolens-cli"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.2.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "geolens"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.2.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-55178"
],
"database_specific": {
"cwe_ids": [
"CWE-200",
"CWE-639",
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-18T18:00:07Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### 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 \u2014 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\u0027s **vector tile data** (actual feature geometries/attributes),\n- the dataset\u0027s **raster pixels**,\n- backing-table **rows**,\n- and **metadata** \u2014 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\u0027s backing dataset. A public map that references a private dataset\nleaked that dataset\u0027s 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 \u2014\nso the signature is **replayable** to read the private dataset\u0027s actual vector\ntiles. *(Anonymous \u00b7 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\u0027s id/title and the relationship id) and then call the\nrelated-record endpoint to read **rows from the private target\u0027s backing\ntable**. *(Anonymous \u00b7 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** \u2014 the user\nwas never threaded into the lookup. An anonymous caller could read any\nprivate, restricted, or unpublished dataset\u0027s metadata by UUID. *(Anonymous \u00b7\nHigh)*\n\n**4. Cross-tenant raster pixel disclosure via VRT mosaics \u2014 SEC-C (PR #237)**\nAn authenticated user with the default `editor` upload permission could mosaic\nanother user\u0027s **private raster** into a VRT they own, then read the victim\u0027s\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` \u00b7 High)*\n\n**5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints \u2014 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\u0027s\ntitle, summary, source URL, filename, column schema, and **sample values** into\nthe response. *(Authenticated `editor` \u00b7 High)*\n\n**6. Residual VRT member disclosure for legacy links \u2014 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` \u2014 fix(catalog): authorize relationship targets in related-record endpoints (#234)\n- `01bc87da` \u2014 fix(maps): re-authorize each layer\u0027s dataset on anonymous map read endpoints (#235)\n- `407c0688` \u2014 fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)\n- `2c031da8` \u2014 fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)\n- `07dfb1c6` \u2014 fix(ai): authorize the requested dataset on AI metadata endpoints (#238)\n\nThe fixes follow the codebase\u0027s 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` \u00b7 CLI: `geolens-cli==1.2.3` \u00b7 npm: `@geolens/sdk@1.2.3`",
"id": "GHSA-p23g-mvhj-jh3j",
"modified": "2026-08-18T18:00:08Z",
"published": "2026-08-18T18:00:07Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/security/advisories/GHSA-p23g-mvhj-jh3j"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/234"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/235"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/236"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/237"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/238"
},
{
"type": "PACKAGE",
"url": "https://github.com/geolens-io/geolens"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data"
}
PYSEC-2026-3662
Vulnerability from pysec - Published: 2026-08-19 11:56 - Updated: 2026-08-19 12:16Summary
Multiple GeoLens read/link endpoints authorized only the resource named in the request URL (a map, a VRT, a source dataset, an AI request) and failed to re-authorize a second, caller-influenced dataset that the request reached through a relationship, layer reference, mosaic source, or request body. This "authorize the URL resource, read a different dataset un-re-authorized" pattern let callers read data from datasets they have no access to.
The most severe instances require no authentication at all (anonymous,
network-only). Others require only the default editor role that any
self-service signup / upload user receives.
All issues are fixed in 1.2.3. There is no complete configuration workaround — upgrading is the only full remediation.
Impact
Depending on the endpoint, an attacker can read, for datasets they cannot otherwise access:
- the dataset's vector tile data (actual feature geometries/attributes),
- the dataset's raster pixels,
- backing-table rows,
- and metadata — table name, column schema, feature count, extent, source URL/filename, contacts, and sampled row values.
Affected versions
All versions prior to 1.2.3 (includes the published 1.0.0, 1.2.0, and 1.2.2 releases and their PyPI/npm/GHCR artifacts). Fixed in 1.2.3.
Findings
1. Anonymous metadata + private vector-tile disclosure via public maps (PR #235)
GET /maps/{id} and GET /maps/{id}/style.json authorized the map but not
each layer's backing dataset. A public map that references a private dataset
leaked that dataset's table name, column schema, feature count, extent, and
sampled values to anonymous callers. style.json additionally returned a
vector-tile URL carrying an HMAC signature bound to neither user nor map,
which the tile endpoint accepts for non-public datasets with no user check —
so the signature is replayable to read the private dataset's actual vector
tiles. (Anonymous · High)
2. Anonymous private-row disclosure via dataset relationships (PR #234) The dataset FK-relationship APIs authorized only the source dataset from the URL, never the relationship target. A public dataset with a relationship to a private dataset let an anonymous caller enumerate the relationship (obtaining the private target's id/title and the relationship id) and then call the related-record endpoint to read rows from the private target's backing table. (Anonymous · High)
3. Anonymous metadata disclosure via OGC externalId lookup (PR #236)
GET /collections/datasets/items?externalId=<uuid> resolved the dataset by id
and returned the full OGC catalog record (title, summary, bbox, keywords,
contacts, distributions, source org) with no visibility check — the user
was never threaded into the lookup. An anonymous caller could read any
private, restricted, or unpublished dataset's metadata by UUID. (Anonymous ·
High)
4. Cross-tenant raster pixel disclosure via VRT mosaics — SEC-C (PR #237)
An authenticated user with the default editor upload permission could mosaic
another user's private raster into a VRT they own, then read the victim's
pixels back through raster tile / quicklook / COG endpoints that authorize
only the attacker-owned VRT. VRT member pixels are compiled into one served
asset and cannot be filtered at read time, so the fix authorizes every source
dataset at write/link time. (Authenticated editor · High)
5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints — SEC-D (PR #238)
The POST /ai/metadata/{summary,keywords,lineage,quality-statement} endpoints
were gated only by the use_ai_chat permission (held by the default editor
role). The attacker-controlled dataset_id in the request body flowed into the
LLM prompt context with no visibility filter, rendering any dataset's
title, summary, source URL, filename, column schema, and sample values into
the response. (Authenticated editor · High)
6. Residual VRT member disclosure for legacy links — SEC-E (PR #237)
Link-time authorization (finding 4) does not re-authorize pre-existing
vrt_source_links, so legacy or authorization-drift links still leaked member
metadata and health via the VRT source-listing/status endpoints until a
per-member read filter was added. (Medium)
Patches
Fixed in 1.2.3 by, in order:
31a103b9— fix(catalog): authorize relationship targets in related-record endpoints (#234)01bc87da— fix(maps): re-authorize each layer's dataset on anonymous map read endpoints (#235)407c0688— fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)2c031da8— fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)07dfb1c6— fix(ai): authorize the requested dataset on AI metadata endpoints (#238)
The fixes follow the codebase's established per-dataset re-authorization pattern
(can_access_dataset / check_dataset_access_or_anonymous), filtering at read
time and authorizing cross-dataset references at link/write time.
Workarounds
There is no complete configuration workaround; the anonymous findings require only network access to the API. Operators who cannot upgrade immediately should restrict network exposure of the API and avoid co-locating private datasets with public maps/relationships, but upgrading to 1.2.3 is the only full remediation.
Remediation
Upgrade to GeoLens 1.2.3:
- Container images: ghcr.io/geolens-io/geolens-api:1.2.3 (+ worker/frontend)
- Python SDK: geolens==1.2.3 · CLI: geolens-cli==1.2.3 · npm: @geolens/sdk@1.2.3
| Name | purl | geolens | pkg:pypi/geolens |
|---|
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "geolens",
"purl": "pkg:pypi/geolens"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.2.3"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"0.0.0",
"1.0.0",
"1.2.0"
]
}
],
"aliases": [
"CVE-2026-55178",
"GHSA-p23g-mvhj-jh3j"
],
"details": "### 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 \u2014 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\u0027s **vector tile data** (actual feature geometries/attributes),\n- the dataset\u0027s **raster pixels**,\n- backing-table **rows**,\n- and **metadata** \u2014 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\u0027s backing dataset. A public map that references a private dataset\nleaked that dataset\u0027s 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 \u2014\nso the signature is **replayable** to read the private dataset\u0027s actual vector\ntiles. *(Anonymous \u00b7 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\u0027s id/title and the relationship id) and then call the\nrelated-record endpoint to read **rows from the private target\u0027s backing\ntable**. *(Anonymous \u00b7 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** \u2014 the user\nwas never threaded into the lookup. An anonymous caller could read any\nprivate, restricted, or unpublished dataset\u0027s metadata by UUID. *(Anonymous \u00b7\nHigh)*\n\n**4. Cross-tenant raster pixel disclosure via VRT mosaics \u2014 SEC-C (PR #237)**\nAn authenticated user with the default `editor` upload permission could mosaic\nanother user\u0027s **private raster** into a VRT they own, then read the victim\u0027s\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` \u00b7 High)*\n\n**5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints \u2014 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\u0027s\ntitle, summary, source URL, filename, column schema, and **sample values** into\nthe response. *(Authenticated `editor` \u00b7 High)*\n\n**6. Residual VRT member disclosure for legacy links \u2014 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` \u2014 fix(catalog): authorize relationship targets in related-record endpoints (#234)\n- `01bc87da` \u2014 fix(maps): re-authorize each layer\u0027s dataset on anonymous map read endpoints (#235)\n- `407c0688` \u2014 fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)\n- `2c031da8` \u2014 fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)\n- `07dfb1c6` \u2014 fix(ai): authorize the requested dataset on AI metadata endpoints (#238)\n\nThe fixes follow the codebase\u0027s 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` \u00b7 CLI: `geolens-cli==1.2.3` \u00b7 npm: `@geolens/sdk@1.2.3`",
"id": "PYSEC-2026-3662",
"modified": "2026-08-19T12:16:24.722815Z",
"published": "2026-08-19T11:56:27.504188Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/security/advisories/GHSA-p23g-mvhj-jh3j"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/234"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/235"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/236"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/237"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/238"
},
{
"type": "PACKAGE",
"url": "https://github.com/geolens-io/geolens"
},
{
"type": "PACKAGE",
"url": "https://pypi.org/project/geolens"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-p23g-mvhj-jh3j"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-55178"
}
],
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data"
}
PYSEC-2026-3663
Vulnerability from pysec - Published: 2026-08-19 11:56 - Updated: 2026-08-19 12:16Summary
Multiple GeoLens read/link endpoints authorized only the resource named in the request URL (a map, a VRT, a source dataset, an AI request) and failed to re-authorize a second, caller-influenced dataset that the request reached through a relationship, layer reference, mosaic source, or request body. This "authorize the URL resource, read a different dataset un-re-authorized" pattern let callers read data from datasets they have no access to.
The most severe instances require no authentication at all (anonymous,
network-only). Others require only the default editor role that any
self-service signup / upload user receives.
All issues are fixed in 1.2.3. There is no complete configuration workaround — upgrading is the only full remediation.
Impact
Depending on the endpoint, an attacker can read, for datasets they cannot otherwise access:
- the dataset's vector tile data (actual feature geometries/attributes),
- the dataset's raster pixels,
- backing-table rows,
- and metadata — table name, column schema, feature count, extent, source URL/filename, contacts, and sampled row values.
Affected versions
All versions prior to 1.2.3 (includes the published 1.0.0, 1.2.0, and 1.2.2 releases and their PyPI/npm/GHCR artifacts). Fixed in 1.2.3.
Findings
1. Anonymous metadata + private vector-tile disclosure via public maps (PR #235)
GET /maps/{id} and GET /maps/{id}/style.json authorized the map but not
each layer's backing dataset. A public map that references a private dataset
leaked that dataset's table name, column schema, feature count, extent, and
sampled values to anonymous callers. style.json additionally returned a
vector-tile URL carrying an HMAC signature bound to neither user nor map,
which the tile endpoint accepts for non-public datasets with no user check —
so the signature is replayable to read the private dataset's actual vector
tiles. (Anonymous · High)
2. Anonymous private-row disclosure via dataset relationships (PR #234) The dataset FK-relationship APIs authorized only the source dataset from the URL, never the relationship target. A public dataset with a relationship to a private dataset let an anonymous caller enumerate the relationship (obtaining the private target's id/title and the relationship id) and then call the related-record endpoint to read rows from the private target's backing table. (Anonymous · High)
3. Anonymous metadata disclosure via OGC externalId lookup (PR #236)
GET /collections/datasets/items?externalId=<uuid> resolved the dataset by id
and returned the full OGC catalog record (title, summary, bbox, keywords,
contacts, distributions, source org) with no visibility check — the user
was never threaded into the lookup. An anonymous caller could read any
private, restricted, or unpublished dataset's metadata by UUID. (Anonymous ·
High)
4. Cross-tenant raster pixel disclosure via VRT mosaics — SEC-C (PR #237)
An authenticated user with the default editor upload permission could mosaic
another user's private raster into a VRT they own, then read the victim's
pixels back through raster tile / quicklook / COG endpoints that authorize
only the attacker-owned VRT. VRT member pixels are compiled into one served
asset and cannot be filtered at read time, so the fix authorizes every source
dataset at write/link time. (Authenticated editor · High)
5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints — SEC-D (PR #238)
The POST /ai/metadata/{summary,keywords,lineage,quality-statement} endpoints
were gated only by the use_ai_chat permission (held by the default editor
role). The attacker-controlled dataset_id in the request body flowed into the
LLM prompt context with no visibility filter, rendering any dataset's
title, summary, source URL, filename, column schema, and sample values into
the response. (Authenticated editor · High)
6. Residual VRT member disclosure for legacy links — SEC-E (PR #237)
Link-time authorization (finding 4) does not re-authorize pre-existing
vrt_source_links, so legacy or authorization-drift links still leaked member
metadata and health via the VRT source-listing/status endpoints until a
per-member read filter was added. (Medium)
Patches
Fixed in 1.2.3 by, in order:
31a103b9— fix(catalog): authorize relationship targets in related-record endpoints (#234)01bc87da— fix(maps): re-authorize each layer's dataset on anonymous map read endpoints (#235)407c0688— fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)2c031da8— fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)07dfb1c6— fix(ai): authorize the requested dataset on AI metadata endpoints (#238)
The fixes follow the codebase's established per-dataset re-authorization pattern
(can_access_dataset / check_dataset_access_or_anonymous), filtering at read
time and authorizing cross-dataset references at link/write time.
Workarounds
There is no complete configuration workaround; the anonymous findings require only network access to the API. Operators who cannot upgrade immediately should restrict network exposure of the API and avoid co-locating private datasets with public maps/relationships, but upgrading to 1.2.3 is the only full remediation.
Remediation
Upgrade to GeoLens 1.2.3:
- Container images: ghcr.io/geolens-io/geolens-api:1.2.3 (+ worker/frontend)
- Python SDK: geolens==1.2.3 · CLI: geolens-cli==1.2.3 · npm: @geolens/sdk@1.2.3
| Name | purl | geolens-cli | pkg:pypi/geolens-cli |
|---|
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "geolens-cli",
"purl": "pkg:pypi/geolens-cli"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.2.3"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"1.0.0",
"1.2.0"
]
}
],
"aliases": [
"CVE-2026-55178",
"GHSA-p23g-mvhj-jh3j"
],
"details": "### 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 \u2014 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\u0027s **vector tile data** (actual feature geometries/attributes),\n- the dataset\u0027s **raster pixels**,\n- backing-table **rows**,\n- and **metadata** \u2014 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\u0027s backing dataset. A public map that references a private dataset\nleaked that dataset\u0027s 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 \u2014\nso the signature is **replayable** to read the private dataset\u0027s actual vector\ntiles. *(Anonymous \u00b7 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\u0027s id/title and the relationship id) and then call the\nrelated-record endpoint to read **rows from the private target\u0027s backing\ntable**. *(Anonymous \u00b7 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** \u2014 the user\nwas never threaded into the lookup. An anonymous caller could read any\nprivate, restricted, or unpublished dataset\u0027s metadata by UUID. *(Anonymous \u00b7\nHigh)*\n\n**4. Cross-tenant raster pixel disclosure via VRT mosaics \u2014 SEC-C (PR #237)**\nAn authenticated user with the default `editor` upload permission could mosaic\nanother user\u0027s **private raster** into a VRT they own, then read the victim\u0027s\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` \u00b7 High)*\n\n**5. Cross-tenant metadata/sample-data disclosure via AI metadata endpoints \u2014 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\u0027s\ntitle, summary, source URL, filename, column schema, and **sample values** into\nthe response. *(Authenticated `editor` \u00b7 High)*\n\n**6. Residual VRT member disclosure for legacy links \u2014 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` \u2014 fix(catalog): authorize relationship targets in related-record endpoints (#234)\n- `01bc87da` \u2014 fix(maps): re-authorize each layer\u0027s dataset on anonymous map read endpoints (#235)\n- `407c0688` \u2014 fix(ogc): enforce dataset visibility on the externalId OGC item lookup (#236)\n- `2c031da8` \u2014 fix(vrt): authorize VRT source datasets at link time + filter unauthorized members on read (#237)\n- `07dfb1c6` \u2014 fix(ai): authorize the requested dataset on AI metadata endpoints (#238)\n\nThe fixes follow the codebase\u0027s 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` \u00b7 CLI: `geolens-cli==1.2.3` \u00b7 npm: `@geolens/sdk@1.2.3`",
"id": "PYSEC-2026-3663",
"modified": "2026-08-19T12:16:24.659936Z",
"published": "2026-08-19T11:56:27.453934Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/security/advisories/GHSA-p23g-mvhj-jh3j"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/234"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/235"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/236"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/237"
},
{
"type": "WEB",
"url": "https://github.com/geolens-io/geolens/pull/238"
},
{
"type": "PACKAGE",
"url": "https://github.com/geolens-io/geolens"
},
{
"type": "PACKAGE",
"url": "https://pypi.org/project/geolens-cli"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-p23g-mvhj-jh3j"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-55178"
}
],
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "GeoLens: Cross-dataset authorization bypass discloses private dataset metadata, schema, sample values, table rows, and raster/vector tile data"
}