VYPR
High severityCISA KEVNVD Advisory· Published Dec 7, 2021· Updated Oct 21, 2025

Grafana path traversal

CVE-2021-43798

Description

Grafana is an open-source platform for monitoring and observability. Grafana versions 8.0.0-beta1 through 8.3.0 (except for patched versions) iss vulnerable to directory traversal, allowing access to local files. The vulnerable URL path is: <grafana_host_url>/public/plugins//, where is the plugin ID for any installed plugin. At no time has Grafana Cloud been vulnerable. Users are advised to upgrade to patched versions 8.0.7, 8.1.8, 8.2.7, or 8.3.1. The GitHub Security Advisory contains more information about vulnerable URL paths, mitigation, and the disclosure timeline.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/grafana/grafanaGo
>= 8.3.0, < 8.3.18.3.1
github.com/grafana/grafanaGo
>= 8.2.0, < 8.2.78.2.7
github.com/grafana/grafanaGo
>= 8.1.0, < 8.1.88.1.8
github.com/grafana/grafanaGo
>= 8.0.0-beta1, < 8.0.78.0.7

Affected products

1

Patches

1
c798c0e958d1

Security: Fix directory traversal issue (#42846)

https://github.com/grafana/grafanaDimitris SotirakisDec 7, 2021via ghsa
2 files changed · +43 3
  • pkg/api/plugins.go+16 3 modified
    @@ -289,14 +289,27 @@ func (hs *HTTPServer) getPluginAssets(c *models.ReqContext) {
     		return
     	}
     
    -	requestedFile := filepath.Clean(web.Params(c.Req)["*"])
    -	pluginFilePath := filepath.Join(plugin.PluginDir, requestedFile)
    +	// prepend slash for cleaning relative paths
    +	requestedFile := filepath.Clean(filepath.Join("/", web.Params(c.Req)["*"]))
    +	rel, err := filepath.Rel("/", requestedFile)
    +	if err != nil {
    +		// slash is prepended above therefore this is not expected to fail
    +		c.JsonApiErr(500, "Failed to get the relative path", err)
    +		return
    +	}
     
    -	if !plugin.IncludedInSignature(requestedFile) {
    +	if !plugin.IncludedInSignature(rel) {
     		hs.log.Warn("Access to requested plugin file will be forbidden in upcoming Grafana versions as the file "+
     			"is not included in the plugin signature", "file", requestedFile)
     	}
     
    +	absPluginDir, err := filepath.Abs(plugin.PluginDir)
    +	if err != nil {
    +		c.JsonApiErr(500, "Failed to get plugin absolute path", nil)
    +		return
    +	}
    +
    +	pluginFilePath := filepath.Join(absPluginDir, rel)
     	// It's safe to ignore gosec warning G304 since we already clean the requested file path and subsequently
     	// use this with a prefix of the plugin's directory, which is set during plugin loading
     	// nolint:gosec
    
  • pkg/api/plugins_test.go+27 0 modified
    @@ -23,9 +23,13 @@ func Test_GetPluginAssets(t *testing.T) {
     	pluginDir := "."
     	tmpFile, err := ioutil.TempFile(pluginDir, "")
     	require.NoError(t, err)
    +	tmpFileInParentDir, err := ioutil.TempFile("..", "")
    +	require.NoError(t, err)
     	t.Cleanup(func() {
     		err := os.RemoveAll(tmpFile.Name())
     		assert.NoError(t, err)
    +		err = os.RemoveAll(tmpFileInParentDir.Name())
    +		assert.NoError(t, err)
     	})
     	expectedBody := "Plugin test"
     	_, err = tmpFile.WriteString(expectedBody)
    @@ -61,6 +65,29 @@ func Test_GetPluginAssets(t *testing.T) {
     			})
     	})
     
    +	t.Run("Given a request for a relative path", func(t *testing.T) {
    +		p := plugins.PluginDTO{
    +			JSONData: plugins.JSONData{
    +				ID: pluginID,
    +			},
    +			PluginDir: pluginDir,
    +		}
    +		service := &fakePluginStore{
    +			plugins: map[string]plugins.PluginDTO{
    +				pluginID: p,
    +			},
    +		}
    +		l := &logger{}
    +
    +		url := fmt.Sprintf("/public/plugins/%s/%s", pluginID, tmpFileInParentDir.Name())
    +		pluginAssetScenario(t, "When calling GET on", url, "/public/plugins/:pluginId/*", service, l,
    +			func(sc *scenarioContext) {
    +				callGetPluginAsset(sc)
    +
    +				require.Equal(t, 404, sc.resp.Code)
    +			})
    +	})
    +
     	t.Run("Given a request for an existing plugin file that is not listed as a signature covered file", func(t *testing.T) {
     		p := plugins.PluginDTO{
     			JSONData: plugins.JSONData{
    

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

13

News mentions

0

No linked articles in our index yet.