Skip to content

Commit 7e79faf

Browse files
committed
Fix code injection vulnerability in basemap provider selection
Replace unsafe eval() with a whitelist dictionary approach for basemap providers. The previous code allowed arbitrary code execution if the source parameter was user-controlled. Security fix: CVE-style code injection via eval()
1 parent 0496942 commit 7e79faf

1 file changed

Lines changed: 29 additions & 13 deletions

File tree

gridfia/visualization/boundaries.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -350,21 +350,37 @@ def add_basemap(
350350
elif isinstance(crs, CRS):
351351
crs = crs.to_string()
352352

353-
# Get tile provider
353+
# Get tile provider using safe whitelist approach
354+
# Security: Never use eval() with user-supplied input
355+
BASEMAP_PROVIDERS = {
356+
'OpenStreetMap': lambda: ctx.providers.OpenStreetMap.Mapnik,
357+
'OpenStreetMap.Mapnik': lambda: ctx.providers.OpenStreetMap.Mapnik,
358+
'OpenStreetMap.HOT': lambda: ctx.providers.OpenStreetMap.HOT,
359+
'CartoDB': lambda: ctx.providers.CartoDB.Positron,
360+
'CartoDB.Positron': lambda: ctx.providers.CartoDB.Positron,
361+
'CartoDB.DarkMatter': lambda: ctx.providers.CartoDB.DarkMatter,
362+
'CartoDB_dark': lambda: ctx.providers.CartoDB.DarkMatter,
363+
'Stamen': lambda: ctx.providers.Stamen.Terrain,
364+
'Stamen.Terrain': lambda: ctx.providers.Stamen.Terrain,
365+
'Stamen.Toner': lambda: ctx.providers.Stamen.Toner,
366+
'Stamen.TonerLite': lambda: ctx.providers.Stamen.TonerLite,
367+
'Stamen.Watercolor': lambda: ctx.providers.Stamen.Watercolor,
368+
'ESRI': lambda: ctx.providers.Esri.WorldImagery,
369+
'Esri.WorldImagery': lambda: ctx.providers.Esri.WorldImagery,
370+
'Esri.WorldStreetMap': lambda: ctx.providers.Esri.WorldStreetMap,
371+
'Esri.WorldTopoMap': lambda: ctx.providers.Esri.WorldTopoMap,
372+
'Esri.NatGeoWorldMap': lambda: ctx.providers.Esri.NatGeoWorldMap,
373+
}
374+
354375
if isinstance(source, str):
355-
if source == 'OpenStreetMap':
356-
provider = ctx.providers.OpenStreetMap.Mapnik
357-
elif source == 'CartoDB':
358-
provider = ctx.providers.CartoDB.Positron
359-
elif source == 'CartoDB_dark':
360-
provider = ctx.providers.CartoDB.DarkMatter
361-
elif source == 'Stamen':
362-
provider = ctx.providers.Stamen.Terrain
363-
elif source == 'ESRI':
364-
provider = ctx.providers.Esri.WorldImagery
376+
if source in BASEMAP_PROVIDERS:
377+
provider = BASEMAP_PROVIDERS[source]()
365378
else:
366-
# Try to get from ctx.providers
367-
provider = eval(f"ctx.providers.{source}")
379+
available = ', '.join(sorted(BASEMAP_PROVIDERS.keys()))
380+
raise ValueError(
381+
f"Unknown basemap source: '{source}'. "
382+
f"Available options: {available}"
383+
)
368384
else:
369385
provider = source
370386

0 commit comments

Comments
 (0)