commit abb14d1 (7.2.0-SNAPSHOT); reproduced on graylog/graylog:7.1.4
Summary
Graylog's URL allowlist (UrlAllowlistService) is the sole SSRF mitigation for every user-configurable outbound-URL feature: HTTP event notifications, and HTTP JSON path / DSV lookup table data adapters. The allowlist check is performed once, against the URL string configured by the user, before the request is issued. None of the HTTP clients used by these features disable following HTTP redirects. As a result, if the allowlisted URL (an external, admin-approved endpoint) ever responds with a 3xx redirect, the underlying OkHttp client transparently follows it to any destination, including internal-only services or the cloud metadata address 169.254.169.254, with no re-validation against the allowlist. A restricted, non-admin user who can create a lookup table data adapter or an event notification can exploit this to make the Graylog server issue requests to arbitrary internal destinations and read the response body directly through the lookup-table query API.
Details
HTTPJSONPathDataAdapter.doGet() performs the allowlist check only on the pre-redirect URL string:
// graylog2-server/src/main/java/org/graylog2/lookup/adapters/HTTPJSONPathDataAdapter.java:158-168
final String urlString = templateEngine.transform(config.url(), ImmutableMap.of("key", encodedKey));
if (!urlAllowlistService.isAllowlisted(urlString)) {
LOG.error("Data adapter <{}>: URL <{}> is not allowlisted. Aborting lookup request.", name(), urlString);
publishSystemNotificationForAllowlistFailure();
setError(UrlNotAllowlistedException.forUrl(urlString));
return getErrorResult();
}
...
try (final Response response = httpClient.newCall(request).execute()) {
httpClient is provided by OkHttpClientProvider, which never calls .followRedirects(false), so OkHttp's default (follow 3xx responses, including cross-host) applies. The response body is parsed and returned directly to the caller (parseBody, same file, lines 224-278), including whatever content the final, unvalidated redirect target returned.
DSVHTTPDataAdapter's file-fetch path is worse: it explicitly re-enables redirects:
// graylog2-server/src/main/java/org/graylog2/lookup/adapters/dsvhttp/HTTPFileRetriever.java:38-45
public HTTPFileRetriever(OkHttpClient httpClient) {
this.client = httpClient.newBuilder()
.followRedirects(true)
.followSslRedirects(true)
.build();
}
HTTPEventNotification/HTTPEventNotificationV2 (used for both saved and "test" webhook notifications) go through the same shared OkHttpClientProvider/ParameterizedHttpClientProvider, so the same bypass applies there too.
Reachability by non-admin users:
POST /system/lookup/adapters (create a data adapter) requires only RestPermissions.LOOKUP_TABLES_CREATE.
GET /system/lookup/adapters/{name}/query (trigger the lookup and read the result) requires only RestPermissions.LOOKUP_TABLES_READ.
POST /events/notifications/test (fire an unsaved HTTP notification test) requires only RestPermissions.EVENT_NOTIFICATIONS_CREATE.
None of these three permissions is admin-only; all are ordinary, independently assignable capabilities.
PoC
(available upon request)
Impact
Any user with the routine, non-admin lookuptables:create+lookuptables:read (or eventnotifications:create) permissions can turn a correctly-configured URL allowlist into a full SSRF primitive with response-body read access. In production deployments where any allowlisted endpoint is attacker-influenceable (an attacker-controlled webhook receiver used for testing, a third-party SaaS integration with an open redirect, or simply a DNS/routing change after the allowlist was written) this allows the Graylog server to be used to reach and read from internal-only services, including cloud instance metadata endpoints, effectively defeating the allowlist that exists specifically to prevent this class of attack.
commit abb14d1 (7.2.0-SNAPSHOT); reproduced on graylog/graylog:7.1.4
Summary
Graylog's URL allowlist (
UrlAllowlistService) is the sole SSRF mitigation for every user-configurable outbound-URL feature: HTTP event notifications, and HTTP JSON path / DSV lookup table data adapters. The allowlist check is performed once, against the URL string configured by the user, before the request is issued. None of the HTTP clients used by these features disable following HTTP redirects. As a result, if the allowlisted URL (an external, admin-approved endpoint) ever responds with a 3xx redirect, the underlying OkHttp client transparently follows it to any destination, including internal-only services or the cloud metadata address169.254.169.254, with no re-validation against the allowlist. A restricted, non-admin user who can create a lookup table data adapter or an event notification can exploit this to make the Graylog server issue requests to arbitrary internal destinations and read the response body directly through the lookup-table query API.Details
HTTPJSONPathDataAdapter.doGet()performs the allowlist check only on the pre-redirect URL string:httpClientis provided byOkHttpClientProvider, which never calls.followRedirects(false), so OkHttp's default (follow 3xx responses, including cross-host) applies. The response body is parsed and returned directly to the caller (parseBody, same file, lines 224-278), including whatever content the final, unvalidated redirect target returned.DSVHTTPDataAdapter's file-fetch path is worse: it explicitly re-enables redirects:HTTPEventNotification/HTTPEventNotificationV2(used for both saved and "test" webhook notifications) go through the same sharedOkHttpClientProvider/ParameterizedHttpClientProvider, so the same bypass applies there too.Reachability by non-admin users:
POST /system/lookup/adapters(create a data adapter) requires onlyRestPermissions.LOOKUP_TABLES_CREATE.GET /system/lookup/adapters/{name}/query(trigger the lookup and read the result) requires onlyRestPermissions.LOOKUP_TABLES_READ.POST /events/notifications/test(fire an unsaved HTTP notification test) requires onlyRestPermissions.EVENT_NOTIFICATIONS_CREATE.None of these three permissions is admin-only; all are ordinary, independently assignable capabilities.
PoC
(available upon request)
Impact
Any user with the routine, non-admin
lookuptables:create+lookuptables:read(oreventnotifications:create) permissions can turn a correctly-configured URL allowlist into a full SSRF primitive with response-body read access. In production deployments where any allowlisted endpoint is attacker-influenceable (an attacker-controlled webhook receiver used for testing, a third-party SaaS integration with an open redirect, or simply a DNS/routing change after the allowlist was written) this allows the Graylog server to be used to reach and read from internal-only services, including cloud instance metadata endpoints, effectively defeating the allowlist that exists specifically to prevent this class of attack.