mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-10 05:24:20 +00:00
fix(image): keep origin enforcement when skipping
This commit is contained in:
2 files changed
+48
-25
No files matched your search
@@ -246,37 +246,38 @@ class RegistryAdapter(ABC):
|
||||
message=f"URL has no host: {canonical_url}",
|
||||
)
|
||||
|
||||
if _outbound_check_skipped():
|
||||
return canonical_url
|
||||
|
||||
try:
|
||||
ipaddress.ip_address(host)
|
||||
except ValueError:
|
||||
# Only the address classification is skipped. The origin rule below still
|
||||
# applies: a registry-supplied URL pointing at an unrelated host is a
|
||||
# different problem from deliberately reaching a private network.
|
||||
if not _outbound_check_skipped():
|
||||
try:
|
||||
infos = socket.getaddrinfo(host, None)
|
||||
except socket.gaierror:
|
||||
infos = []
|
||||
for *_, sockaddr in infos:
|
||||
resolved_ip = sockaddr[0]
|
||||
if _ip_is_non_public(resolved_ip) and not self._ip_is_allowed(
|
||||
resolved_ip
|
||||
):
|
||||
ipaddress.ip_address(host)
|
||||
except ValueError:
|
||||
try:
|
||||
infos = socket.getaddrinfo(host, None)
|
||||
except socket.gaierror:
|
||||
infos = []
|
||||
for *_, sockaddr in infos:
|
||||
resolved_ip = sockaddr[0]
|
||||
if _ip_is_non_public(resolved_ip) and not self._ip_is_allowed(
|
||||
resolved_ip
|
||||
):
|
||||
raise ImageRegistryAuthError(
|
||||
file=__file__,
|
||||
message=(
|
||||
f"Host {host!r} resolves to non-public address "
|
||||
f"{resolved_ip}. {_ALLOWLIST_HINT}"
|
||||
),
|
||||
)
|
||||
else:
|
||||
if _ip_is_non_public(host) and not self._ip_is_allowed(host):
|
||||
raise ImageRegistryAuthError(
|
||||
file=__file__,
|
||||
message=(
|
||||
f"Host {host!r} resolves to non-public address "
|
||||
f"{resolved_ip}. {_ALLOWLIST_HINT}"
|
||||
f"URL targets a non-public address: {host}. "
|
||||
f"{_ALLOWLIST_HINT}"
|
||||
),
|
||||
)
|
||||
else:
|
||||
if _ip_is_non_public(host) and not self._ip_is_allowed(host):
|
||||
raise ImageRegistryAuthError(
|
||||
file=__file__,
|
||||
message=(
|
||||
f"URL targets a non-public address: {host}. "
|
||||
f"{_ALLOWLIST_HINT}"
|
||||
),
|
||||
)
|
||||
|
||||
if enforce_origin:
|
||||
registry_host = urlparse(origin_url or self._origin_url()).hostname or ""
|
||||
|
||||
@@ -610,6 +610,28 @@ class TestOutboundCheckOptOut:
|
||||
|
||||
mock_request.assert_not_called()
|
||||
|
||||
@patch("prowler.providers.image.lib.registry.base.requests.request")
|
||||
def test_the_origin_rule_still_applies_when_skipped(
|
||||
self, mock_request, monkeypatch
|
||||
):
|
||||
"""Skipping the address check must not let a registry redirect us elsewhere."""
|
||||
monkeypatch.setenv("PROWLER_SKIP_OUTBOUND_HOST_CHECK", "true")
|
||||
adapter = OciRegistryAdapter(registry_url="https://registry.example.com")
|
||||
|
||||
with pytest.raises(ImageRegistryAuthError, match="unrelated to registry host"):
|
||||
adapter._validate_outbound_url("https://attacker.example.net/token")
|
||||
|
||||
mock_request.assert_not_called()
|
||||
|
||||
@patch("prowler.providers.image.lib.registry.base.requests.request")
|
||||
def test_a_same_origin_url_is_allowed_when_skipped(self, mock_request, monkeypatch):
|
||||
monkeypatch.setenv("PROWLER_SKIP_OUTBOUND_HOST_CHECK", "true")
|
||||
adapter = OciRegistryAdapter(registry_url="https://registry.example.com")
|
||||
|
||||
assert adapter._validate_outbound_url(
|
||||
"https://registry.example.com/v2/token"
|
||||
).startswith("https://registry.example.com/")
|
||||
|
||||
@patch("prowler.providers.image.lib.registry.base.requests.request")
|
||||
def test_the_scheme_check_still_applies_when_skipped(
|
||||
self, mock_request, monkeypatch
|
||||
|
||||
Reference in new issue
Block a user