Prevent path traversal in the asset serving REST resources (7.0) - #26987
Draft
graylog-internal-actions-access[bot] wants to merge 1 commit into
Draft
Prevent path traversal in the asset serving REST resources (7.0)#26987graylog-internal-actions-access[bot] wants to merge 1 commit into
7.0)#26987graylog-internal-actions-access[bot] wants to merge 1 commit into
Conversation
* Prevent path traversal in the asset serving REST resources `PreflightAssetsResource` and `ResourceFileReader` concatenated a user-supplied filename into a classpath resource lookup without validating it. The JAX-RS path templates match against the encoded path segment, so a literal `../` never matches, but a percent-encoded one does and is decoded before it reaches the resource method. Resource names are now resolved against their base directory, normalized, and required to address a direct child of it. A direct child rather than mere containment, because `Path#normalize` collapses leading `..` on an absolute path, which makes containment meaningless for plugin assets: those are packaged at the root of the plugin JAR, and `/` contains every path. That alone still lets a traversal land on an unrelated JAR's root-level resource, so plugin assets additionally have to originate from the code source of the plugin that is being asked for them. `PreflightAssetsResource` duplicated `ResourceFileReader` almost verbatim. It now injects it instead, so the check lives in a single place. Neither resource reflects the requested file name back to the client anymore; it goes to a debug log. See GHSA-7v9x-j5xj-57rq for details. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Add changelog snippet for #26942 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Improving changelog snippet. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Tomas Dvorak <tomas.dvorak@graylog.com> (cherry picked from commit 4654f70)
graylog-internal-actions-access
Bot
requested review from
moesterheld and
todvora
August 14, 2026 14:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note: This is a backport of #26942 to
7.0.Description
Validates the user-supplied filename in the asset serving REST resources before it reaches a classpath resource lookup.
ResourceFileReader.resolveResourceNameresolves the filename against its base directory, normalizes it, and requires the result to be a direct child of that base. A direct child rather than mere containment below the base, becausePath#normalizecollapses leading..on an absolute path — which makes a containment check meaningless for plugin assets, since those are packaged at the root of the plugin JAR and/contains every path.That alone still lets a traversal land on an unrelated JAR's root-level resource (
/../../log4j2.xmlnormalizes to the perfectly root-level/log4j2.xml), so plugin assets additionally have to originate from the code source of the plugin being asked for them.PreflightAssetsResourceduplicatedResourceFileReaderalmost verbatim — same GuavaFileSystemcache, samefile/jarswitch. It now injects it instead, so the check lives in exactly one place for all three call sites. Neither resource reflects the requested file name back to the client anymore; it goes to a debug log.Fixes https://github.com/Graylog2/graylog-plugin-enterprise/issues/15006.
Motivation and Context
PreflightAssetsResourceandResourceFileReaderconcatenated a user-supplied filename intogetResource(...)with no validation. The JAX-RS path templates match against the encoded path segment, so a literal../never matches — but a percent-encoded one does, and Jersey decodes@PathParamvalues before injection.Of the two,
WebInterfaceAssetsResourcematters more: it runs on the normal server and its asset routes are not permission-annotated.PreflightAssetsResourceis only reachable before a node is configured and sits behindBasicAuthFilter.How Has This Been Tested?
Screenshots (if appropriate):
Types of changes
Checklist: