{"record":{"id":"a20e3dc45cead371","repo":"juanfont/headscale","slug":"0-0-0-0-0-and-0-are-not-allowed","errorCode":null,"errorMessage":"0.0.0.0/0 and ::/0 are not allowed","messagePattern":"0\\.0\\.0\\.0/0 and ::/0 are not allowed","errorType":"validation","errorClass":"errTrustedProxyZeroRange","httpStatus":null,"severity":"error","filePath":"hscontrol/types/config.go","lineNumber":42,"sourceCode":"\t\"tailscale.com/util/set\"\n)\n\nconst (\n\tPKCEMethodPlain string = \"plain\"\n\tPKCEMethodS256  string = \"S256\"\n\n\tdefaultNodeStoreBatchSize = 100\n)\n\nvar (\n\terrOidcMutuallyExclusive     = errors.New(\"oidc_client_secret and oidc_client_secret_path are mutually exclusive\")\n\terrOIDCIssuerInvalid         = errors.New(\"oidc.issuer must be a valid http(s) URL\")\n\terrOIDCClientIDRequired      = errors.New(\"oidc.client_id is required when oidc.issuer is set\")\n\terrOIDCClientSecretRequired  = errors.New(\"oidc.client_secret or oidc.client_secret_path is required when oidc.issuer is set\")\n\terrServerURLSuffix           = errors.New(\"server_url cannot be part of base_domain in a way that could make the DERP and headscale server unreachable\")\n\terrServerURLSame             = errors.New(\"server_url cannot use the same domain as base_domain in a way that could make the DERP and headscale server unreachable\")\n\terrInvalidPKCEMethod         = errors.New(\"pkce.method must be either 'plain' or 'S256'\")\n\terrTrustedProxyZeroRange     = errors.New(\"0.0.0.0/0 and ::/0 are not allowed\")\n\tErrNoPrefixConfigured        = errors.New(\"no IPv4 or IPv6 prefix configured, minimum one prefix is required\")\n\tErrInvalidAllocationStrategy = errors.New(\"invalid prefix allocation strategy\")\n)\n\ntype IPAllocationStrategy string\n\nconst (\n\tIPAllocationStrategySequential IPAllocationStrategy = \"sequential\"\n\tIPAllocationStrategyRandom     IPAllocationStrategy = \"random\"\n)\n\ntype PolicyMode string\n\nconst (\n\tPolicyModeDB   = \"database\"\n\tPolicyModeFile = \"file\"\n)\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/types/config.go#L24-L60","documentation":"errTrustedProxyZeroRange is a sentinel error in hscontrol/types/config.go that rejects the catch-all CIDRs 0.0.0.0/0 and ::/0 in the trusted_proxies config list. Headscale trusts proxies listed there to supply the real client IP via X-Forwarded-For / X-Real-Ip headers; trusting every address means any client can spoof its IP and bypass source-IP checks. It is returned at config load time (config.go:1080, wrapped as `trusted_proxies[%d] %q: ...`), so the server refuses to start.","triggerScenarios":"Setting trusted_proxies: [\"0.0.0.0/0\"] or [\"::/0\"] in config.yaml and running `headscale serve`; LoadConfig parses each entry with netip.ParsePrefix and hits the zero-range check at hscontrol/types/config.go:1080.","commonSituations":"Copying a reverse-proxy example config and pasting 0.0.0.0/0 to 'trust everything'; upgrading from an older headscale that silently tolerated it; misunderstanding the option as an ACL allowlist instead of an HTTP proxy trust list.","solutions":["List only the specific reverse-proxy addresses/CIDRs, e.g. trusted_proxies: [\"127.0.0.1/32\", \"192.168.1.0/24\"]","If headscale is directly exposed with no reverse proxy, remove trusted_proxies entirely","Run `headscale config verify` (or start the server) after editing to confirm the config passes validation"],"exampleFix":"# before\ntrusted_proxies:\n  - 0.0.0.0/0\n\n# after (only the actual proxy)\ntrusted_proxies:\n  - 127.0.0.1/32\n  - 172.17.0.0/16","handlingStrategy":"validation","validationCode":"// before starting headscale, sanity-check the config value\nfor _, p := range cfg.TLS.TrustedProxies { // or your trusted_proxies slice\n\tparsed, err := netip.ParsePrefix(p)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bad trusted_proxies entry %q: %w\", p, err)\n\t}\n\tif parsed == netip.MustParsePrefix(\"0.0.0.0/0\") || parsed == netip.MustParsePrefix(\"::/0\") {\n\t\treturn fmt.Errorf(\"trusted_proxies must not contain catch-all ranges, got %q\", p)\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never put 0.0.0.0/0 or ::/0 in trusted_proxies; list only the reverse proxy's actual address or CIDR","Run `headscale config verify` in CI for every config change","Treat trusted_proxies as an HTTP header-trust list, not an allowlist"],"tags":["config","networking","validation","reverse-proxy"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}