CVE-2021-43815 (Go, published 2021-12-10T21:15Z)
Description: value: Grafana is an open-source platform for monitoring and observability. Grafana prior to versions 8.3.2 and 7.5.12 has a directory traversal for arbitrary .csv files. It only affects instances that have the developer testing tool called TestData DB data source enabled and configured. The vulnerability is limited in scope, and only allows access to files with the extension .csv to authenticated users only. Grafana Cloud instances have not been affected by the vulnerability. Versions 8.3.2 and 7.5.12 contain a patch for this issue. There is a workaround available for users who cannot upgrade. Running a reverse proxy in front of Grafana that normalizes the PATH of the request will mitigate the vulnerability. The proxy will have to also be able to handle url encoded paths.
Severity: LOW (CVSS v3 base score: 4.3)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/grafana/grafana
Files changed:
pkg/api/plugins.go
pkg/tsdb/testdatasource/csv_data.go
Commit message: Backport fix to main (#42979)

* fixes

(cherry picked from commit a2c386915ce11b9422f4af8ae181eaa1a22bc5c3)
(cherry picked from commit 06706efbbe59ad9d3075835cc31e2f734e36df95)

* fix regex

(cherry picked from commit a259213a3badc9618e969f2c8db0a0143f00faee)
(cherry picked from commit 1d7105c0959df2083814237024f7ec098a76099b)

* lint (#42970)

(cherry picked from commit afb9e8e5f3c33fa59c5a1053d98d8d97815af002)

Co-authored-by: Will Browne <will.browne@grafana.com>
Co-authored-by: malcolmholmes <42545407+malcolmholmes@users.noreply.github.com>

Vulnerable code:
	// We can ignore the gosec G304 warning on this one because `plugin.PluginDir` is based
	// on plugin the folder structure on disk and not user input.
	path := filepath.Join(plugin.PluginDir, fmt.Sprintf("%s.md", strings.ToUpper(name)))
		path = filepath.Join(plugin.PluginDir, fmt.Sprintf("%s.md", strings.ToLower(name)))
	// We can ignore the gosec G304 warning on this one because `plugin.PluginDir` is based
	// on plugin the folder structure on disk and not user input.
	validFileName := regexp.MustCompile(`([\w_]+)\.csv`)
	filePath := filepath.Join(s.cfg.StaticRootPath, "testdata", fileName)

Fixed code:
	// We can ignore the gosec G304 warning since we have cleaned the requested file path and subsequently
	// use this with a prefix of the plugin's directory, which is set during plugin loading
	path := filepath.Join(plugin.PluginDir, mdFilepath(strings.ToUpper(name)))
		path = filepath.Join(plugin.PluginDir, mdFilepath(strings.ToLower(name)))
	// We can ignore the gosec G304 warning since we have cleaned the requested file path and subsequently
	// use this with a prefix of the plugin's directory, which is set during plugin loading

func mdFilepath(mdFilename string) string {
	return filepath.Clean(filepath.Join("/", fmt.Sprintf("%s.md", mdFilename)))
}
	validFileName := regexp.MustCompile(`^\w+\.csv$`)
	csvFilepath := filepath.Clean(filepath.Join("/", fileName))
	filePath := filepath.Join(s.cfg.StaticRootPath, "testdata", csvFilepath)