Validar a URL como texto não é validar o host; fragmento, query, userinfo e codificações enganam a checagem.
A defesa correta é uma lista de permissão de hosts. O erro comum é validar a URL do jeito errado, olhando o TEXTO em vez do destino real. O caso clássico é a checagem por substring: "aceite se a URL contiver estancia.test". Mas uma URL tem partes que não mudam o host: o fragmento (depois de #) e a query (depois de ?). Então http://127.0.0.1:9000/admin#estancia.test contém o texto permitido e passa, mas o host real é 127.0.0.1.
Outras armadilhas da mesma família:
userinfo: em http://[email protected]/, o host é o que vem DEPOIS do @ (127.0.0.1); o estancia.test é só um nome de usuário.
codificação de IP: 127.0.0.1 também é 2130706433 (decimal) ou 0x7f000001 (hexa). Uma lista que bloqueia o texto 127.0.0.1 não vê a forma decimal.
http vs https, redirecionamento: checar só o esquema não restringe o host, e seguir um redirecionamento de um host permitido leva a qualquer lugar.
A regra: analise a URL de verdade, extraia o host, resolva o IP e compare o IP RESOLVIDO com a lista. Nunca decida pelo texto.
A checagem por substring vê estancia.test no fragmento e aprova; o cliente HTTP ignora o fragmento e conecta no host real, 127.0.0.1.