SonarSource/sonarqube · error · IllegalArgumentException

Invalid URL: loopback, wildcard, link-local, site-local…

Error message

Invalid URL: loopback, wildcard, link-local, site-local, multicast, cloud metadata addresses and addresses of the SonarQube server itself are not allowed for webhooks.

What it means

Thrown by WebhookSupport.checkUrlPattern (via WebhookAddressValidator.INVALID_ADDRESS_MESSAGE) when the resolved webhook host points to a blocked address: loopback, wildcard, link-local, site-local, multicast, cloud metadata, or the SonarQube server itself. This SSRF protection applies when sonar.validate.webhooks (or the configured property) is enabled, which is the default.

Solutions

  1. Use a public HTTPS URL for the webhook receiver, or a DNS name that resolves to a public address.
  2. If internal webhooks are intentionally required, set sonar.validate.webhooks=false in sonar.properties (understand the SSRF trade-off) and restart.
  3. Expose the internal receiver through a public reverse proxy/relay instead.

Example fix

// before
curl -u $TOKEN -X POST "$SONAR/api/webhooks/create?name=ci&url=http://localhost:9001/hook" // blocked
// after
# allow internal (trusted network) by disabling validation in sonar.properties:
# sonar.validate.webhooks=false
curl -u $TOKEN -X POST "$SONAR/api/webhooks/create?name=ci&url=https://ci.example.com/sonarqube/hook"
Defensive patterns

Strategy: validation

Validate before calling

InetAddress addr = InetAddress.getByName(host);
if (addr.isLoopbackAddress() || addr.isAnyLocalAddress() || addr.isLinkLocalAddress()
    || addr.isSiteLocalAddress() || addr.isMulticastAddress()
    || host.equals("169.254.169.254")) {
  throw new IllegalArgumentException("Webhook URL points to a blocked/internal address");
}

Try / catch

try {
  createWebhook(name, url);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("not allowed for webhooks")) {
    throw new ConfigurationException("Use a public webhook URL or disable sonar.validate.webhooks for trusted internal networks");
  }
}

Prevention

When it happens

Trigger: Creating/updating a webhook whose URL host resolves to 127.0.0.1/localhost, 0.0.0.0, 169.254.x.x (including the 169.254.169.254 cloud metadata endpoint), 10.x/172.16-31.x/192.168.x addresses, multicast ranges, or the SonarQube server's own address.

Common situations: Pointing webhooks at an internal CI listener (e.g. http://localhost:9001/hook) in a containerized/on-prem setup; administrators disabling the validation property to allow internal hosts when they control the network; Kubernetes setups where the internal service IP is site-local.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/8dccfdf82c7e9f10. Report an issue: GitHub.

Appendix: source

Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/webhook/ws/WebhookSupport.java:68

    userSession.checkEntityPermission(ProjectPermission.ADMIN, projectDto);
  }

  void checkPermission() {
    userSession.checkPermission(GlobalPermission.ADMINISTER);
  }

  void checkUrlPattern(String url, String message, Object... messageArguments) {
    try {
      HttpUrl okUrl = HttpUrl.parse(url);
      if (okUrl == null) {
        throw new IllegalArgumentException(String.format(message, messageArguments));
      }
      InetAddress address = InetAddress.getByName(okUrl.host());

      if (configuration.getBoolean(SONAR_VALIDATE_WEBHOOKS_PROPERTY)
        .orElse(SONAR_VALIDATE_WEBHOOKS_DEFAULT_VALUE)
        && WebhookAddressValidator.isBlockedAddress(address, networkInterfaceProvider)) {
        throw new IllegalArgumentException(WebhookAddressValidator.INVALID_ADDRESS_MESSAGE);
      }
    } catch (UnknownHostException e) {
      // if a host can not be resolved the deliveries will fail - no need to block it from being set
      // this will only happen for public URLs
    } catch (SocketException e) {
      throw new IllegalStateException("Can not retrieve a network interfaces", e);
    }
  }
}

View on GitHub (pinned to 184c821202)