Coordinated Disclosure Timeline
- 2024-06-17: Sent the report to the maintainerβs email.
- 2024-07-19: Sent a follow up email asking for an update. Received an answer with the fix and was asked to request the CVEs for the issues.
- 2024-07-19: GitHub Security Lab assigns CVEs to the vulnerabilities.
Summary
Streamlit-geospatial project contains several remote code execution and blind server-side request forgery vulnerabilities.
Project
streamlit-geospatial
Tested Version
latest
Details
Issue 1: Remote code execution in pages/1_π·_Timelapse.py Any Earth Engine ImageCollection option palette (GHSL-2024-100)
The palette variable in pages/1_π·_Timelapse.py takes user input, which is later used in the eval() function on line 380, leading to remote code execution.
palette = st.text_area(
"Enter a custom palette:",
palette_values,
)
st.write(
cm.plot_colormap(cmap=palette_options, return_fig=True)
)
st.session_state["palette"] = eval(palette)
Impact
This issue may lead to remote code execution.
PoC
- Start streamlit-geospatial
- Go to π· Timelapse tab and:
- in
Select a satellite image collection:chooseAny Earth Engine Image Collection - in
Enter an ee.ImageCollection asset ID:typeECMWF/CAMS/NRT
- in
- Open
Customize band combination and color paletteand paste intoEnter a custom palette:__import__('code').InteractiveInterpreter().runsource('import os;os.system(\"echo $(uname -a) > foobar.txt\")') - Observe in the server, that a file foobar.txt has been created, and contains the output of the command
uname -a.
Issue 2: Remote code execution in pages/1_π·_Timelapse.py Any Earth Engine ImageCollection option vis_params (GHSL-2024-101)
The vis_params variable on line 383 or line 390 in pages/1_π·_Timelapse.py takes user input, which is later used in the eval() function on line 395, leading to remote code execution.
if bands:
vis_params = st.text_area(
"Enter visualization parameters",
"{'bands': ["
+ ", ".join([f"'{band}'" for band in bands])
+ "]}",
)
else:
vis_params = st.text_area(
"Enter visualization parameters",
"{}",
)
try:
st.session_state["vis_params"] = eval(vis_params)
Impact
This issue may lead to remote code execution.
PoC
- Start streamlit-geospatial
- Go to π· Timelapse tab and:
- in
Select a satellite image collection:chooseAny Earth Engine Image Collection - in
Enter an ee.ImageCollection asset ID:typeECMWF/CAMS/NRT
- in
- Open
Customize band combination and color paletteand paste intoEnter visualization parameters:__import__('code').InteractiveInterpreter().runsource('import os;os.system(\"echo $(uname -a) > foobar.txt\")') - Observe in the server, that a file foobar.txt has been created, and contains the output of the command
uname -a.
Issue 3: Remote code execution in pages/1_π·_Timelapse.py MODIS Gap filled Land Surface Temperature Daily option (GHSL-2024-102)
The palette variable on line 430 in pages/1_π·_Timelapse.py takes user input, which is later used in the eval() function on line 435, leading to remote code execution.
palette = st.text_area(
"Enter a custom palette:",
palette_values,
)
st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
st.session_state["palette"] = eval(palette)
Impact
This issue may lead to remote code execution.
PoC
- Start streamlit-geospatial
- Go to π· Timelapse tab and in
Select a satellite image collection:chooseMODIS Gap filled Land Surface Temperature Daily - Paste into
Enter a custom palette:__import__('code').InteractiveInterpreter().runsource('import os;os.system(\"echo $(uname -a) > foobar.txt\")') - Observe in the server, that a file foobar.txt has been created, and contains the output of the command
uname -a.
Issue 4: Remote code execution in pages/1_π·_Timelapse.py MODIS Ocean Color SMI option palette (GHSL-2024-103)
The palette variable on line 488 in pages/1_π·_Timelapse.py takes user input, which is later used in the eval() function on line 493, leading to remote code execution.
palette = st.text_area(
"Enter a custom palette:",
palette_values,
)
st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
st.session_state["palette"] = eval(palette)
Impact
This issue may lead to remote code execution.
PoC
- Start streamlit-geospatial
- Go to π· Timelapse tab and in
Select a satellite image collection:chooseMODIS Ocean Color SMI - Paste into
Enter a custom palette:__import__('code').InteractiveInterpreter().runsource('import os;os.system(\"echo $(uname -a) > foobar.txt\")') - Observe in the server, that a file foobar.txt has been created, and contains the output of the command
uname -a.
Issue 5: Remote code execution in pages/1_π·_Timelapse.py MODIS Ocean Color SMI option vis_params (GHSL-2024-104)
The vis_params variable on line 1254 in pages/1_π·_Timelapse.py takes user input, which is later used in the eval() function on line 1345, leading to remote code execution.
vis_params = st.text_area(
"Enter visualization parameters",
"",
help="Enter a string in the format of a dictionary, such as '{'min': 23, 'max': 32}'",
)
--- snip
elif collection == "MODIS Ocean Color SMI":
if vis_params.startswith("{") and vis_params.endswith(
"}"
):
vis_params = eval(vis_params)
Impact
This issue may lead to remote code execution.
PoC
- Start streamlit-geospatial
- Go to π· Timelapse tab and:
- in
Select a satellite image collection:chooseMODIS Ocean Color SMI - in
Select a sample ROI or upload a GeoJSON filechooseWorld
- in
- Open
Customize timelapseand paste intoEnter visualization parameters:{__import__('code').InteractiveInterpreter().runsource('import os;os.system(\"echo $(uname -a) > foobar.txt\")')} - Observe in the server, that a file foobar.txt has been created, and contains the output of the command
uname -a.
Issue 6: Remote code execution in pages/10_π_Earth_Engine_Datasets.py (GHSL-2024-105)
The vis_params variable on line 115 in pages/10_π_Earth_Engine_Datasets.py takes user input, which is later used in the eval() function on line 126, leading to remote code execution.
vis_params = st.text_input(
"Enter visualization parameters as a dictionary", {}
)
layer_name = st.text_input("Enter a layer name", uid)
button = st.button("Add dataset to map")
if button:
vis = {}
try:
if vis_params.strip() == "":
# st.error("Please enter visualization parameters")
vis_params = "{}"
vis = eval(vis_params)
Impact
This issue may lead to remote code execution.
PoC
- Start streamlit-geospatial
- Go to π Earth Engine Datasets tab and in
Enter a keyword to search (e.g., elevation)typeelevation - Paste into
Enter visualization parameters as a dictionary:__import__('code').InteractiveInterpreter().runsource('import os;os.system(\"echo $(uname -a) > foobar.txt\")') - Observe in the server, that a file foobar.txt has been created, and contains the output of the command
uname -a.
Issue 7: Remote code execution in pages/8_ποΈ_Raster_Data_Visualization.py (GHSL-2024-107)
The vis_params variable on line 80 in 8_ποΈ_Raster_Data_Visualization.py takes user input, which is later used in the eval() function on line 86, leading to remote code execution.
add_params = st.checkbox("Add visualization parameters")
if add_params:
vis_params = st.text_area("Enter visualization parameters", "{}")
else:
vis_params = {}
if len(vis_params) > 0:
try:
vis_params = eval(vis_params)
Impact
This issue may lead to remote code execution.
PoC
- Start streamlit-geospatial
- Go to ποΈ Raster Data Visualization tab and select
Add visualization parameters. - Paste into
Enter visualization parameters:__import__('code').InteractiveInterpreter().runsource('import os;os.system(\"echo $(uname -a) > foobar.txt\")') - Observe in the server, that a file foobar.txt has been created, and contains the output of the command
uname -a.
Issue 8: Blind SSRF in pages/7_π¦_Web_Map_Service.py (GHSL-2024-106)
The url variable on line 47 takes user input, which is passed to get_layers function, in which url is used with get_wms_layer method. get_wms_layer method creates a request to arbitrary destinations, leading to blind server-side request forgery.
@st.cache_data
def get_layers(url):
options = leafmap.get_wms_layers(url)
return options
--- snip
url = st.text_input(
"Enter a WMS URL:", value="https://services.terrascope.be/wms/v2"
)
empty = st.empty()
if url:
options = get_layers(url)
Impact
This issue allows for sending requests on behalf of the streamlit-geospatial server and can be leveraged to probe for other vulnerabilities on the server itself or on other back-end systems on the internal network, that the streamlit-geospatial server can reach.
See also: https://portswigger.net/web-security/ssrf/blind
PoC
- Start streamlit-geospatial.
- Create a new folder with a file
file.txt. Start a simple HTTP server in the folder by executingpython -m http.server. It will start a server on 127.0.0.1:8000. - Go to π¦ Web Map Service tab and in
Enter a WMS URL:typehttp://127.0.0.1:8000/file.txt - Observe that a request to the file was logged in the python server.
Issue 9: Blind SSRF in pages/9_π²_Vector_Data_Visualization.py (GHSL-2024-108)
The url variable on line 63 takes user input, which is later passed to the gpd.read_file method. gpd.read_file method creates a request to arbitrary destinations, leading to blind server-side request forgery.
url = empty.text_input(
"Enter a HTTP URL to a Cloud Optimized GeoTIFF (COG)",
cog,
)
if url:
try:
options = leafmap.cog_bands(url)
Impact
This issue allows for sending requests on behalf of the streamlit-geospatial server and can be leveraged to probe for other vulnerabilities on the server itself or on other back-end systems on the internal network, that the streamlit-geospatial server can reach.
See also: https://portswigger.net/web-security/ssrf/blind
PoC
- Start streamlit-geospatial.
- Create a new folder with a file
file.txt. Start a simple HTTP server in the folder by executingpython -m http.server. It will start a server on 127.0.0.1:8000. - Go to π² Vector Data Visualization tab and in
Enter a URL to a vector datasettypehttp://127.0.0.1:8000/file.txt - Observe that a request to the file was logged in the python server.
CVE
- GHSL-2024-100 - CVE-2024-41112
- GHSL-2024-101 - CVE-2024-41113
- GHSL-2024-102 - CVE-2024-41114
- GHSL-2024-103 - CVE-2024-41115
- GHSL-2024-104 - CVE-2024-41116
- GHSL-2024-105 - CVE-2024-41117
- GHSL-2024-106 - CVE-2024-41118
- GHSL-2024-107 - CVE-2024-41119
- GHSL-2024-108 - CVE-2024-41120
Credit
These issues were discovered and reported by GHSL team member @sylwia-budzynska (Sylwia Budzynska).
Contact
You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2024-100, GHSL-2024-101, GHSL-2024-102, GHSL-2024-103, GHSL-2024-104, GHSL-2024-105, GHSL-2024-106, GHSL-2024-107, or GHSL-2024-108 in any communication regarding these issues.