Harden DAV outbound URL validation (#2819)

This commit is contained in:
Vykos
2026-06-05 13:22:21 +02:00
committed by GitHub
parent 6d64055328
commit 370ae5d451
7 changed files with 326 additions and 22 deletions
+46 -1
View File
@@ -1,4 +1,5 @@
import asyncio
import ipaddress
import sys
import types
from pathlib import Path
@@ -8,7 +9,12 @@ import pytest
from src import caldav_sync
def test_validate_caldav_url_normalizes_safe_url():
def test_validate_caldav_url_normalizes_safe_url(monkeypatch):
monkeypatch.setattr(
caldav_sync,
"_resolve_caldav_host_ips",
lambda host: [ipaddress.ip_address("93.184.216.34")],
)
assert (
caldav_sync.validate_caldav_url(" https://calendar.example.com/dav/ ")
== "https://calendar.example.com/dav"
@@ -42,7 +48,46 @@ def test_validate_caldav_url_blocks_private_ips_unless_explicitly_allowed(monkey
assert caldav_sync.validate_caldav_url("http://10.0.0.5:5232/dav") == "http://10.0.0.5:5232/dav"
def test_validate_caldav_url_blocks_dns_to_private(monkeypatch):
monkeypatch.delenv("ODYSSEUS_ALLOW_PRIVATE_CALDAV", raising=False)
monkeypatch.setattr(
caldav_sync,
"_resolve_caldav_host_ips",
lambda host: [ipaddress.ip_address("10.0.0.5")],
)
with pytest.raises(ValueError, match="Private CalDAV IPs require"):
caldav_sync.validate_caldav_url("https://calendar.example.com/dav")
def test_validate_caldav_url_blocks_dns_to_link_local_even_when_private_allowed(monkeypatch):
monkeypatch.setenv("ODYSSEUS_ALLOW_PRIVATE_CALDAV", "1")
monkeypatch.setattr(
caldav_sync,
"_resolve_caldav_host_ips",
lambda host: [ipaddress.ip_address("169.254.169.254")],
)
with pytest.raises(ValueError, match="host is not allowed"):
caldav_sync.validate_caldav_url("https://calendar.example.com/dav")
def test_validate_caldav_url_fails_closed_when_hostname_does_not_resolve(monkeypatch):
def _no_dns(host):
raise OSError("no such host")
monkeypatch.setattr(caldav_sync, "_resolve_caldav_host_ips", _no_dns)
with pytest.raises(ValueError, match="host does not resolve"):
caldav_sync.validate_caldav_url("https://calendar.example.com/dav")
def test_sync_caldav_decrypts_stored_password_and_validates_url(monkeypatch):
monkeypatch.setattr(
caldav_sync,
"_resolve_caldav_host_ips",
lambda host: [ipaddress.ip_address("93.184.216.34")],
)
prefs_mod = types.ModuleType("routes.prefs_routes")
prefs_mod._load_for_user = lambda owner: {
"caldav": {