Graylog2 / Graylog2/graylog2-server

HTTP redirects bypass the URL allowlist in lookup table data adapters and event notifications, enabling non-admin SSRF and internal data exfiltration

Open
#26,591 1 comment 0 reactions 0 assignees View on GitHub
bug security triaged
Dominant language
Java
Stars
8.1k
Forks
1.1k
Avg merge
1d 20h
Merged PRs (30d)
217

Description

commit abb14d1c (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:

```java
// 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:

```java
// 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.

Contributor guide

Open the contributing guide

Research direction

Trace HTTPJSONPathDataAdapter.java, dsvhttp/HTTPFileRetriever.java, HTTPEventNotification/HTTPEventNotificationV2, and the shared OkHttpClientProvider/ParameterizedHttpClientProvider. Verify how redirects are handled after the allowlist check and cover lookup and notification flows. Done means redirected requests cannot bypass URL validation and the affected responses remain protected.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.