VYPR
Low severityNVD Advisory· Published Aug 31, 2023· Updated Sep 27, 2024

Partial path traversal vulnerability in Support Bundle feature of Graylog

CVE-2023-41044

Description

Graylog is a free and open log management platform. A partial path traversal vulnerability exists in Graylog's Support Bundle feature. The vulnerability is caused by incorrect user input validation in an HTTP API resource. Graylog's Support Bundle feature allows an attacker with valid Admin role credentials to download or delete files in sibling directories of the support bundle directory. The default data_dir in operating system packages (DEB, RPM) is set to /var/lib/graylog-server. The data directory for the Support Bundle feature is always <data_dir>/support-bundle. Due to the partial path traversal vulnerability, an attacker with valid Admin role credentials can read or delete files in directories that start with a /var/lib/graylog-server/support-bundle directory name. The vulnerability would allow the download or deletion of files in the following example directories: /var/lib/graylog-server/support-bundle-test and /var/lib/graylog-server/support-bundlesdirectory. For the Graylog Docker images, the data_dir is set to /usr/share/graylog/data by default. This vulnerability is fixed in Graylog version 5.1.3 and later. Users are advised to upgrade. Users unable to upgrade should block all HTTP requests to the following HTTP API endpoints by using a reverse proxy server in front of Graylog. GET /api/system/debug/support/bundle/download/{filename} and DELETE /api/system/debug/support/bundle/{filename}.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.graylog2:graylog2-serverMaven
>= 5.1.0, < 5.1.35.1.3

Affected products

1

Patches

1
02b8792e6f4b

Merge pull request from GHSA-2q4p-f6gf-mqr5

https://github.com/Graylog2/graylog2-serverBernd AhlersJul 5, 2023via ghsa
3 files changed · +40 4
  • changelog/unreleased/ghsa-2q4p-f6gf-mqr5.toml+2 0 added
    @@ -0,0 +1,2 @@
    +type = "security"
    +message = "Fix partial path traversal vulnerability in Support Bundle feature. [GHSA-2q4p-f6gf-mqr5](https://github.com/Graylog2/graylog2-server/security/advisories/GHSA-2q4p-f6gf-mqr5)"
    
  • graylog2-server/src/main/java/org/graylog2/rest/resources/system/debug/bundle/SupportBundleService.java+5 4 modified
    @@ -500,7 +500,7 @@ public List<BundleFile> listBundles() {
         }
     
         public void downloadBundle(String filename, OutputStream outputStream) throws IOException {
    -        ensureFileWithinBundleDir(filename);
    +        ensureFileWithinBundleDir(bundleDir, filename);
     
             try {
                 final Path filePath = bundleDir.resolve(filename);
    @@ -512,14 +512,15 @@ public void downloadBundle(String filename, OutputStream outputStream) throws IO
             }
         }
     
    -    private void ensureFileWithinBundleDir(String filename) throws IOException {
    -        if (!bundleDir.resolve(filename).toFile().getCanonicalPath().startsWith(bundleDir.toFile().getCanonicalPath())) {
    +    @VisibleForTesting
    +    void ensureFileWithinBundleDir(Path bundleDir, String filename) {
    +        if (!bundleDir.resolve(filename).toAbsolutePath().normalize().startsWith(bundleDir.toAbsolutePath().normalize())) {
                 throw new NotFoundException();
             }
         }
     
         public void deleteBundle(String filename) throws IOException {
    -        ensureFileWithinBundleDir(filename);
    +        ensureFileWithinBundleDir(bundleDir, filename);
             final Path filePath = bundleDir.resolve(filename);
             Files.delete(filePath);
         }
    
  • graylog2-server/src/test/java/org/graylog2/rest/resources/system/debug/bundle/SupportBundleServiceTest.java+33 0 modified
    @@ -21,17 +21,22 @@
     import org.graylog2.shared.bindings.providers.ObjectMapperProvider;
     import org.junit.jupiter.api.Test;
     import org.junit.jupiter.api.extension.ExtendWith;
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.ValueSource;
     import org.mockito.InjectMocks;
     import org.mockito.Mock;
     import org.mockito.junit.jupiter.MockitoExtension;
     
    +import javax.ws.rs.NotFoundException;
     import java.nio.file.Path;
     import java.time.Instant;
     import java.time.temporal.ChronoUnit;
     import java.util.List;
     import java.util.concurrent.ExecutorService;
     
     import static org.assertj.core.api.Assertions.assertThat;
    +import static org.assertj.core.api.Assertions.assertThatCode;
    +import static org.assertj.core.api.Assertions.assertThatThrownBy;
     
     @ExtendWith(MockitoExtension.class)
     public class SupportBundleServiceTest {
    @@ -95,4 +100,32 @@ public void testLogSizeLimiterWithSpaceForOneZippedFile() {
             assertThat(shrinkedList).hasSize(3);
             assertThat(shrinkedList).extracting(LogFile::id).contains("memory", "0", "1");
         }
    +
    +    @ParameterizedTest
    +    @ValueSource(strings = {"/tmp/safe_dir", "safe_dir", "../safe_dir"})
    +    void ensureWithinBundleDir(String bundleDirString) throws Exception {
    +        final var bundleDir = Path.of(bundleDirString);
    +
    +        assertThatCode(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "file.zip"))
    +                .doesNotThrowAnyException();
    +        assertThatCode(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "hello/file.zip"))
    +                .doesNotThrowAnyException();
    +        assertThatCode(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "hello/world/file.zip"))
    +                .doesNotThrowAnyException();
    +        assertThatCode(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "..file.zip"))
    +                .doesNotThrowAnyException();
    +
    +        assertThatThrownBy(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "/etc/file.zip"))
    +                .isInstanceOf(NotFoundException.class);
    +        assertThatThrownBy(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "/etc/hello/../world/../file.zip"))
    +                .isInstanceOf(NotFoundException.class);
    +        assertThatThrownBy(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "../file.zip"))
    +                .isInstanceOf(NotFoundException.class);
    +        assertThatThrownBy(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "../../file.zip"))
    +                .isInstanceOf(NotFoundException.class);
    +        assertThatThrownBy(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "../safe_dir_insecure/file.zip"))
    +                .isInstanceOf(NotFoundException.class);
    +        assertThatThrownBy(() -> supportBundleService.ensureFileWithinBundleDir(bundleDir, "/safe_dir_insecure/file.zip"))
    +                .isInstanceOf(NotFoundException.class);
    +    }
     }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.