diff --git a/README.md b/README.md index c33e20a..d087b80 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,8 @@ Put the RouterPulse `Update-URL`, `Domainnamen`, `Benutzername`, and `Kennwort` Use a subdomain such as `home.example.com`. Root/apex domains like `example.com` usually cannot be plain CNAME records unless your DNS provider supports CNAME flattening or ALIAS/ANAME records. +The generated hostname is not a secret. Treat it like any public DNS name. The update URL slug, router password, private status page URL, and domain claim link are the secrets. + ## Custom Domain Flow This flow is only needed when RouterPulse should publish A/AAAA records directly inside a user-owned domain instead of using a CNAME target. @@ -274,6 +276,6 @@ Self-hosted DynDNS, self hosted DDNS, Dynamic DNS server, FRITZ!Box DynDNS, FRIT ## Security -The repository intentionally contains only placeholders in `.env.example` and documentation. Do not commit a real `.env`, DNS token, TSIG secret, admin password, database, private status page URL, domain claim URL, or router-generated update URL. +The repository intentionally contains only placeholders in `.env.example` and documentation. Do not commit a real `.env`, DNS token, TSIG secret, admin password, database, private status page URL, domain claim URL, or router-generated update URL. Generated hostnames and CNAME targets are public identifiers, not authentication secrets. If you find a vulnerability, open a private advisory or contact the repository owner before publishing details. diff --git a/tests/test_ddns.py b/tests/test_ddns.py index 6aab1b2..9bff7f6 100644 --- a/tests/test_ddns.py +++ b/tests/test_ddns.py @@ -96,6 +96,25 @@ def test_generated_account_can_update_own_hostname(tmp_path: Path) -> None: assert slug_response.text == "good 203.0.113.10" +def test_generated_hostname_is_not_an_update_secret(tmp_path: Path) -> None: + database_path = tmp_path / "ddns.sqlite3" + store = DdnsStore(database_path) + store.create_account("public-target.ddns.example.net", "alice") + app = make_app(DdnsSettings(database_path=database_path, admin_password="admin")) + client = TestClient(app) + + response = client.get( + "/nic/update", + params={ + "hostname": "public-target.ddns.example.net", + "myip": "203.0.113.9", + }, + ) + + assert response.status_code == 401 + assert store.list_records() == [] + + def test_dns_publish_failure_does_not_update_record(tmp_path: Path, monkeypatch) -> None: def fail_publish(result, settings): raise RuntimeError("dns down")