{"record":{"id":"5cab612989ee58ea","repo":"pinpoint-apm/pinpoint","slug":"webhook-url-resolved-address-is-required","errorCode":null,"errorMessage":"Webhook URL resolved address is required","messagePattern":"Webhook URL resolved address is required","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"commons-server/src/main/java/com/navercorp/pinpoint/common/server/webhook/WebhookUrlValidator.java","lineNumber":171,"sourceCode":"        return rawAuthority.indexOf(':', hostStartIndex) >= 0;\n    }\n\n    private static void validateHostWithoutResolving(String host) {\n        String normalizedHost = normalizeHost(host);\n        if (isBlockedHostName(normalizedHost)) {\n            throw new IllegalArgumentException(\"Webhook URL host is not allowed\");\n        }\n\n        IPAddress address = toHostLiteralAddress(normalizedHost);\n        if (address != null) {\n            validateResolvedAddress(normalizedHost, address.toInetAddress(), WebhookHostPolicy.denyAll());\n        }\n    }\n\n    public static void validateResolvedAddress(String host, InetAddress address, WebhookHostPolicy policy) {\n        Objects.requireNonNull(policy, \"policy\");\n        if (address == null) {\n            throw new IllegalArgumentException(\"Webhook URL resolved address is required\");\n        }\n        if (isBlockedAddress(address)) {\n            throw new IllegalArgumentException(\"Webhook URL resolves to a non-public address\");\n        }\n        if (isPrivateAddress(address) && !isAllowedPrivateHost(host, policy)) {\n            throw new IllegalArgumentException(\"Webhook URL resolves to a private address that is not allowed\");\n        }\n    }\n\n    /**\n     * The policy matches host names only. Allowing an IP literal to match would let a caller\n     * reach an internal address without going through an allowed host name.\n     */\n    private static boolean isAllowedPrivateHost(String host, WebhookHostPolicy policy) {\n        if (host == null) {\n            return false;\n        }\n        String normalizedHost = normalizeHost(host);","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/commons-server/src/main/java/com/navercorp/pinpoint/common/server/webhook/WebhookUrlValidator.java#L153-L189","documentation":"The public validateResolvedAddress requires a non-null resolved InetAddress for the webhook host. A null address means the caller tried to validate a host whose DNS resolution produced no address, so the SSRF address policy cannot be applied. The validator fails fast rather than skipping the security check.","triggerScenarios":"Calling WebhookUrlValidator.validateResolvedAddress (directly, or via validateHostWithoutResolving on an IP literal path) with address == null while policy is non-null.","commonSituations":"Custom code that resolves the webhook host itself (e.g. InetAddress.getByName returning null through a custom resolver, or an empty DNS result set) and then passes the null result into validation.","solutions":["Ensure the host is actually resolved to an InetAddress before calling validateResolvedAddress.","Handle unresolvable hosts separately (fail the webhook config with a DNS error) instead of passing null.","If using a custom resolver, return an Optional/exception on failure rather than a null address."],"exampleFix":"// before\nInetAddress addr = resolver.lookupOrNull(host);\nWebhookUrlValidator.validateResolvedAddress(host, addr, policy);\n// after\nInetAddress addr = resolver.lookup(host); // throws on failure\nObjects.requireNonNull(addr, \"DNS lookup failed for \" + host);\nWebhookUrlValidator.validateResolvedAddress(host, addr, policy);","handlingStrategy":"validation","validationCode":"InetAddress addr = InetAddress.getByName(host);\nif (addr == null) {\n    throw new IllegalArgumentException(\"cannot resolve webhook host: \" + host);\n}","typeGuard":"boolean isResolved(InetAddress a) { return a != null && !a.isAnyLocalAddress(); }","tryCatchPattern":"try {\n    WebhookUrlValidator.validateResolvedAddress(host, addr, policy);\n} catch (IllegalArgumentException e) {\n    log.error(\"Address validation failed for {}: {}\", host, e.getMessage());\n}","preventionTips":["Resolve hosts with a resolver that throws on failure instead of returning null","Check DNS health before registering webhook URLs","Never pass resolution results that may be null directly into validators"],"tags":["dns","webhook","null-check","ssrf"],"backgroundTag":"null-argument","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}