Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
ec17725
fix(dataset-import): validate hostname in import URL allowlist check
sha174n Apr 12, 2026
7e886c6
test(dataset-import): improve branch coverage for hostname validation
sha174n Apr 12, 2026
6f9f625
fix(dataset-import): add missing network ranges and IPv4-mapped IPv6 …
sha174n Apr 12, 2026
dfb304f
fix(dataset-import): validate redirect targets before following HTTP …
sha174n Apr 12, 2026
74a0dda
fix(dataset-import): fix test mocks and code formatting after urlopen…
sha174n Apr 12, 2026
7484965
style(tests): add missing return type annotation to test function
sha174n Apr 12, 2026
8d120df
fix(notifications): add hostname validation to outbound requests in c…
sha174n Apr 12, 2026
0c20ccf
test(impala): fix cancel_query tests to account for hostname validation
sha174n Apr 12, 2026
de45255
style(tests): use tuple form for pytest.mark.parametrize arg names
sha174n Apr 12, 2026
5f87da9
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Apr 14, 2026
273fe1a
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Apr 26, 2026
976afcf
fix(network): restrict file:// URIs in dataset import to examples folder
sha174n Apr 26, 2026
088c4f9
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Apr 27, 2026
595dd90
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 3, 2026
c7b171f
address review feedback
sha174n May 3, 2026
0fd906c
simplify: move os import to module level
sha174n May 3, 2026
9abe2bd
simplify: deduplicate urlparse call in webhook validator
sha174n May 4, 2026
dd11b33
fix(network): resolve relative redirect URLs and remove impala cancel…
sha174n May 5, 2026
9dcd493
fix: enforce HTTP/HTTPS scheme and hostname before SSRF host check in…
sha174n May 5, 2026
fdc321e
fix: revert couchbase hostname check to is_hostname_valid for on-prem…
sha174n May 5, 2026
4624529
fix: revert databricks hostname check and align impala tests with cur…
sha174n May 6, 2026
45d3662
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 10, 2026
da0b1d1
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 13, 2026
04d042e
address review feedback: strengthen is_safe_host and file:// handling
sha174n May 13, 2026
7308d1b
Merge branch 'master' into fix/dataset-import-url-validation
rusackas May 14, 2026
0223c3b
chore(ci): add explicit permissions to additional workflows (#40067)
arpitjain099 May 14, 2026
1cef64d
fix(dashboard): use datasetUuid instead of datasetId in display contr…
fitzee May 14, 2026
d1749ad
fix(mcp): apply cached adhoc filters to chart retrieval (#40099)
richardfogaca May 14, 2026
52c4183
fix(docs): tighten onBrokenLinks to throw and fix surfaced broken lin…
rusackas May 14, 2026
4cc423b
test(datasets): regression coverage for #16141 (export with same tabl…
rusackas May 14, 2026
5292ade
chore(deps): bump react-syntax-highlighter from 16.1.0 to 16.1.1 in /…
dependabot[bot] May 14, 2026
1a4d5fb
chore(deps): update @ant-design/icons requirement from ^6.2.2 to ^6.2…
dependabot[bot] May 14, 2026
3404c6a
chore(deps-dev): bump babel-jest from 30.3.0 to 30.4.1 in /superset-f…
dependabot[bot] May 14, 2026
90ee4f2
fix(sqllab): missing estimate action button (#40101)
justinpark May 14, 2026
d3f0056
fix(database): extend shillelagh URI pattern to cover all driver vari…
sha174n May 15, 2026
1931bde
fix(query): restrict query cancellation to the query owner (#39996)
sha174n May 15, 2026
5cc649f
fix(dataset): validate datasource access during import (#39998)
sha174n May 15, 2026
0276baa
fix(extensions): add cache headers and strip Vary: Cookie for extensi…
michael-s-molina May 15, 2026
a1acb35
fix: escape SQL identifiers in db engine spec prequeries and metadata…
sha174n May 15, 2026
9cd1469
fix(security): harden SSRF blocklist and fail-closed on missing hostname
sha174n May 15, 2026
dc432ab
Merge upstream/master: resolve docs and lock file conflicts
sha174n May 19, 2026
7f7d38e
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 20, 2026
1588f0b
fix: remove unrelated react-syntax-highlighter version change
sha174n May 21, 2026
001bfec
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 22, 2026
2d71687
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 22, 2026
27c6c2b
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 25, 2026
9502e57
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 25, 2026
2d95767
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 26, 2026
4028da4
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 26, 2026
2584416
chore: retrigger CI after transient codecov-action download failure
sha174n May 26, 2026
b34c46b
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 26, 2026
48fba47
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 26, 2026
7f0659f
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 27, 2026
ee3ea54
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 27, 2026
ced9de7
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 28, 2026
6d4b079
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 28, 2026
23c49c5
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 29, 2026
7e1061b
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 29, 2026
181c06e
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 29, 2026
0221ce0
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 30, 2026
6b8b794
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 30, 2026
8d4ed5a
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 30, 2026
966b9e1
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n May 31, 2026
b96f599
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Jun 1, 2026
136c920
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Jun 1, 2026
3e90541
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Jun 1, 2026
97af811
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Jun 2, 2026
3d986ae
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Jun 2, 2026
377d000
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Jun 2, 2026
2d431d5
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
sha174n Jun 2, 2026
4396139
Merge branch 'master' into fix/dataset-import-url-validation
sha174n Jun 2, 2026
4e0ac11
fix(rls,reports): revert databend host swap, gate webhook block behin…
sha174n Jun 3, 2026
83a9f76
fix(impala): validate cancel_query host before outbound HTTP request
sha174n Jun 3, 2026
fbe4927
test(impala): mock is_safe_host in cancel_query happy-path tests
sha174n Jun 3, 2026
313334c
Merge remote-tracking branch 'upstream/master' into fix/dataset-impor…
Jun 11, 2026
2e7e54d
address review feedback: flatten nested conditionals and harden impal…
sha174n Jun 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ assists people when migrating to a new version.

## Next

### Webhook alerts/reports block private/internal hosts by default

Webhook alert/report dispatch (`WebhookNotification.send`) now validates the target URL's host against the same private/internal-IP block applied to dataset import URLs. If the resolved host is in a loopback, link-local, private (RFC-1918), shared-CGNAT, or multicast range, the webhook is rejected with `NotificationParamException`.

Deployments that intentionally point webhooks at internal targets (chatops bridges, internal automation servers, on-premises Mattermost/Rocket.Chat, etc.) can opt out by setting `ALERT_REPORTS_WEBHOOK_ALLOW_INTERNAL_HOSTS = True` in `superset_config.py`. This mirrors the existing `DATASET_IMPORT_ALLOW_INTERNAL_DATA_URLS` opt-out for dataset imports.

### Impala cancel_query blocks private/internal hosts by default

The Impala engine spec's `cancel_query` issues an HTTP request from the Superset backend to the host configured on the Impala database connection. That host is now validated before the request: if it resolves to a private/internal IP range, the cancel call is refused and a warning is logged. Operators whose Impala cluster runs on an internal network can opt out by setting `IMPALA_CANCEL_QUERY_ALLOW_INTERNAL_HOSTS = True` in `superset_config.py`. This mirrors the dataset-import and webhook opt-out flags.
### Map chart renderer and OpenStreetMap migration behavior

The MapLibre migration for deck.gl charts preserves saved non-Mapbox styles on
Expand Down
70 changes: 65 additions & 5 deletions superset/commands/dataset/importers/v1/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
# under the License.
import gzip
import logging
import os
import re
from typing import Any
from urllib import request
from urllib.parse import urljoin, urlparse
from urllib.request import HTTPRedirectHandler

import pandas as pd
from flask import current_app as app
Expand All @@ -40,9 +43,35 @@
from superset.sql.parse import Table
from superset.utils import json
from superset.utils.core import get_user
from superset.utils.network import is_safe_host

logger = logging.getLogger(__name__)


class _ValidatingRedirectHandler(HTTPRedirectHandler):
"""Re-validates the redirect target URL before following any HTTP redirect.

Prevents bypasses where an initial URL passes validation but a subsequent
redirect points to a disallowed destination.
"""

def redirect_request(
self,
req: request.Request,
fp: Any,
code: int,
msg: str,
headers: Any,
newurl: str,
) -> request.Request | None:
"""Validate each redirect target before delegating to the parent handler."""
# Resolve relative redirects against the originating request URL so that
# validate_data_uri receives a fully-qualified URL in all cases.
absolute_url = urljoin(req.full_url, newurl)
validate_data_uri(absolute_url)
return super().redirect_request(req, fp, code, msg, headers, newurl)
Comment thread
sha174n marked this conversation as resolved.


CHUNKSIZE = 512
VARCHAR = re.compile(r"VARCHAR\((\d+)\)", re.IGNORECASE)

Expand Down Expand Up @@ -88,12 +117,33 @@ def get_dtype(df: pd.DataFrame, dataset: SqlaTable) -> dict[str, VisitableType]:

def validate_data_uri(data_uri: str) -> None:
Comment thread
sha174n marked this conversation as resolved.
"""
Validate that the data URI is configured on DATASET_IMPORT_ALLOWED_URLS
has a valid URL.
Validate that the data URI is permitted for dataset import.

Local ``file://`` URIs are allowed only when the path is confined to the
bundled examples folder. All other URIs must match a pattern in
``DATASET_IMPORT_ALLOWED_DATA_URLS`` *and* resolve to a publicly-routable host.

:param data_uri:
:return:
:param data_uri: the URI to validate
:raises DatasetForbiddenDataURI: if the URI is not permitted
"""
if data_uri.startswith("file://"):
from urllib.request import url2pathname

from superset.examples.helpers import get_examples_folder

parsed = urlparse(data_uri)
# Reject non-local authority components (e.g. file://remotehost/path).
if parsed.netloc and parsed.netloc.lower() != "localhost":
raise DatasetForbiddenDataURI()
# url2pathname handles URL-encoded characters and platform path separators.
file_path = url2pathname(parsed.path)
# Resolve symlinks and relative components before comparing.
real_path = os.path.realpath(file_path)
examples_folder = os.path.realpath(get_examples_folder())
if not real_path.startswith(examples_folder + os.sep):
raise DatasetForbiddenDataURI()
return
Comment thread
sha174n marked this conversation as resolved.
Comment thread
sha174n marked this conversation as resolved.

allowed_urls = app.config["DATASET_IMPORT_ALLOWED_DATA_URLS"]
for allowed_url in allowed_urls:
try:
Expand All @@ -104,6 +154,15 @@ def validate_data_uri(data_uri: str) -> None:
)
raise
if match:
allow_internal = app.config.get(
"DATASET_IMPORT_ALLOW_INTERNAL_DATA_URLS", False
)
if not allow_internal:
hostname = urlparse(data_uri).hostname
# Fail-closed: reject URIs that have no parseable hostname as
# well as those that resolve to non-public addresses.
if not hostname or not is_safe_host(hostname):
raise DatasetForbiddenDataURI()
return
raise DatasetForbiddenDataURI()

Expand Down Expand Up @@ -282,7 +341,8 @@ def load_data(data_uri: str, dataset: SqlaTable, database: Database) -> None:

validate_data_uri(data_uri)
logger.info("Downloading data from %s", data_uri)
data = request.urlopen(data_uri) # pylint: disable=consider-using-with # noqa: S310
opener = request.build_opener(_ValidatingRedirectHandler)
data = opener.open(data_uri) # pylint: disable=consider-using-with # noqa: S310
if data_uri.endswith(".gz"):
data = gzip.open(data)
df = pd.read_csv(data, encoding="utf-8")
Expand Down
27 changes: 25 additions & 2 deletions superset/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2053,6 +2053,21 @@ def EMAIL_HEADER_MUTATOR( # pylint: disable=invalid-name,unused-argument # noq
# Enforce HTTPS for webhook alerts/reports
ALERT_REPORTS_WEBHOOK_HTTPS_ONLY = True

# When True, webhook alert/report dispatch is permitted to call private/internal
# IP addresses (RFC-1918, loopback, link-local). Intended for deployments where
# the webhook target is on an internal network (a chatops bridge, an internal
# Mattermost/Rocket.Chat, an automation server, etc.). Leave False (the default)
# in any internet-facing deployment.
ALERT_REPORTS_WEBHOOK_ALLOW_INTERNAL_HOSTS: bool = False

# When True, Impala's cancel_query HTTP call is permitted to target hosts in
# private/internal IP ranges (RFC-1918, loopback, link-local). Intended for
# operators whose Impala cluster runs on an internal network. Leave False (the
# default) in any deployment where untrusted users can create Impala database
# connections, so a maliciously-configured impala:// URL cannot be used to
# trigger outbound requests to internal targets via the cancel endpoint.
IMPALA_CANCEL_QUERY_ALLOW_INTERNAL_HOSTS: bool = False

# A custom prefix to use on all Alerts & Reports emails
EMAIL_REPORTS_SUBJECT_PREFIX = "[Report] "

Expand Down Expand Up @@ -2342,13 +2357,21 @@ def EMAIL_HEADER_MUTATOR( # pylint: disable=invalid-name,unused-argument # noq
# If true all default urls on datasets will be handled as relative URLs by the frontend
PREVENT_UNSAFE_DEFAULT_URLS_ON_DATASET = True

# Define a list of allowed URLs for dataset data imports (v1).
# Define a list of allowed URL patterns (regex) for dataset data imports (v1).
# Simple example to only allow URLs that belong to certain domains:
# ALLOWED_IMPORT_URL_DOMAINS = [
# DATASET_IMPORT_ALLOWED_DATA_URLS = [
# r"^https://.+\.domain1\.com\/?.*", r"^https://.+\.domain2\.com\/?.*"
# ]
# Local file:// URIs used for bundled example data are always permitted
# regardless of this setting.
DATASET_IMPORT_ALLOWED_DATA_URLS = [r".*"]

# When True, dataset import is permitted to fetch data from private/internal
# IP addresses (RFC-1918, loopback, link-local). Intended for air-gapped or
# on-premises deployments where the data source is on an internal network.
# Leave False (the default) in any internet-facing deployment.
DATASET_IMPORT_ALLOW_INTERNAL_DATA_URLS: bool = False

# Path used to store SSL certificates that are generated when using custom certs.
# Defaults to temporary directory.
# Example: SSL_CERT_PATH = "/certs"
Expand Down
16 changes: 16 additions & 0 deletions superset/db_engine_specs/impala.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from superset.constants import QUERY_EARLY_CANCEL_KEY, TimeGrain
from superset.db_engine_specs.base import BaseEngineSpec, DatabaseCategory
from superset.models.sql_lab import Query
from superset.utils.network import is_safe_host

if TYPE_CHECKING:
from superset.models.core import Database
Expand Down Expand Up @@ -209,6 +210,21 @@ def cancel_query(cls, cursor: Any, query: Query, cancel_query_id: str) -> bool:
"""
try:
impala_host = query.database.url_object.host
# The cancel call issues an outbound HTTP request from the
# Superset backend to whatever host the DB connection was
# configured with; validate it before the call to keep this
# path consistent with the dataset-import and webhook URL
# checks. Operators with internal Impala targets can opt out
# via IMPALA_CANCEL_QUERY_ALLOW_INTERNAL_HOSTS.
if not impala_host:
return False
if not app.config[
"IMPALA_CANCEL_QUERY_ALLOW_INTERNAL_HOSTS"
] and not is_safe_host(impala_host):
logger.warning(
"Impala cancel_query refused: target host is not allowed"
)
return False
url = f"http://{impala_host}:25000/cancel_query?query_id={cancel_query_id}"
response = requests.post(url, timeout=3)
except Exception: # pylint: disable=broad-except
Expand Down
32 changes: 27 additions & 5 deletions superset/reports/notifications/webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
)
from superset.utils import json
from superset.utils.decorators import statsd_gauge
from superset.utils.network import is_safe_host

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -93,6 +94,31 @@ def _get_files(self) -> list[tuple[str, tuple[str, bytes, str]]]:
)
return files

def _validate_webhook_url(self, url: str) -> None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Add an inline docstring to this newly introduced method describing what it validates and which exceptions it raises. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

This is a newly introduced Python method and it has no docstring in the final file state.
The provided rule explicitly requires new functions and classes to be documented inline,
so this is a real violation.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset/reports/notifications/webhook.py
**Line:** 97:97
**Comment:**
	*Custom Rule: Add an inline docstring to this newly introduced method describing what it validates and which exceptions it raises.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

parsed = urlparse(url)
if parsed.scheme.lower() not in ("http", "https"):
raise NotificationParamException(
"Webhook failed: only HTTP and HTTPS webhook URLs are supported."
)
if (
current_app.config["ALERT_REPORTS_WEBHOOK_HTTPS_ONLY"]
and parsed.scheme.lower() != "https"
):
raise NotificationParamException(
"Webhook failed: HTTPS is required by config for webhook URLs."
)
if not parsed.hostname:
raise NotificationParamException(
"Webhook failed: URL must include a valid hostname."
)
# Operators with internal webhook targets (chatops bridges, internal
# automation, etc.) can opt out of the private-IP block via
# ALERT_REPORTS_WEBHOOK_ALLOW_INTERNAL_HOSTS.
if current_app.config["ALERT_REPORTS_WEBHOOK_ALLOW_INTERNAL_HOSTS"]:
return
if not is_safe_host(parsed.hostname):
raise NotificationParamException("Webhook URL target host is not allowed.")

@backoff.on_exception(
backoff.expo, NotificationUnprocessableException, factor=10, base=2, max_tries=5
)
Expand All @@ -104,11 +130,7 @@ def send(self) -> None:
is not enabled."
)
wh_url = self._get_webhook_url()
if current_app.config["ALERT_REPORTS_WEBHOOK_HTTPS_ONLY"]:
if urlparse(wh_url).scheme.lower() != "https":
raise NotificationParamException(
"Webhook failed: HTTPS is required by config for webhook URLs."
)
self._validate_webhook_url(wh_url)
payload = self._get_req_payload()
files = self._get_files()

Expand Down
51 changes: 51 additions & 0 deletions superset/utils/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,65 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import ipaddress
import platform
import socket
import subprocess

# Networks that must never be reached via user-supplied hostnames.
# Includes loopback, RFC-1918 private ranges, link-local (covers cloud
# metadata endpoints such as 169.254.169.254), shared address space
# (RFC 6598, 100.64.0.0/10), multicast (ip.is_global returns True for
# multicast addresses in Python, so explicit blocking is required), and
# IPv6 equivalents.
_SSRF_UNSAFE_NETWORKS = (
ipaddress.ip_network("0.0.0.0/8"),
ipaddress.ip_network("10.0.0.0/8"),
ipaddress.ip_network("100.64.0.0/10"),
ipaddress.ip_network("127.0.0.0/8"),
Comment thread
sha174n marked this conversation as resolved.
ipaddress.ip_network("169.254.0.0/16"),
ipaddress.ip_network("172.16.0.0/12"),
ipaddress.ip_network("192.168.0.0/16"),
ipaddress.ip_network("224.0.0.0/4"), # IPv4 multicast — is_global is True in Python
ipaddress.ip_network("::1/128"),
ipaddress.ip_network("fc00::/7"),
ipaddress.ip_network("fe80::/10"),
ipaddress.ip_network("ff00::/8"), # IPv6 multicast
)

PORT_TIMEOUT = 5
PING_TIMEOUT = 5


def is_safe_host(host: str) -> bool:
"""
Return True if ``host`` resolves exclusively to public, globally-routable
IP addresses.

Returns False if any resolved address falls within a private, loopback,
link-local, or otherwise non-routable range. An unresolvable host also
returns False.
"""
try:
results = socket.getaddrinfo(host, None)
except socket.gaierror:
return False
if not results:
return False
for _, _, _, _, sockaddr in results:
try:
ip = ipaddress.ip_address(sockaddr[0])
except ValueError:
Comment thread
sha174n marked this conversation as resolved.
return False
# Unwrap IPv4-mapped IPv6 addresses (e.g. ::ffff:127.0.0.1) so they
# are checked against the IPv4 unsafe networks rather than bypassing.
if isinstance(ip, ipaddress.IPv6Address) and ip.ipv4_mapped:
ip = ip.ipv4_mapped
if not ip.is_global or any(ip in net for net in _SSRF_UNSAFE_NETWORKS):
return False
Comment thread
sha174n marked this conversation as resolved.
return True


def is_port_open(host: str, port: int) -> bool:
"""
Test if a given port in a host is open.
Expand Down
Loading
Loading