CVE-2021-43798 – Path Traversal – Grafana

Grafana es una plataforma de código abierto ampliamente utilizada para el análisis y la monitorización. La vulnerabilidad CVE-2021-43798 permite a actores malintencionados no autenticados leer archivos arbitrarios del sistema de archivos del servidor, aprovechando una debilidad en la forma en que se gestionan las rutas de los complementos (plugins). Esta vulnerabilidad ha sido explotada activamente y ahora figura en el catálogo de vulnerabilidades conocidas explotadas de la CISA. Es fundamental aplicar los parches disponibles de inmediato.

ProductoGrafana, Grafana
Fecha2025-10-10 13:14:42

Resumen técnico

La vulnerabilidad estaba presente en la función getPluginAssets dentro del archivo pkg/api/plugins.go. El código original no realizaba ninguna validación sobre la ruta del archivo solicitado, sino que simplemente tomaba el parámetro de la URL y lo utilizaba para construir una ruta de archivo:

func (hs *HTTPServer) getPluginAssets(c *models.ReqContext) {

  pluginID := web.Params(c.Req)[":pluginId"]

        ...........................

  requestedFile := filepath.Clean(web.Params(c.Req)["*"])

  pluginFilePath := filepath.Join(plugin.PluginDir, requestedFile)

        ...........................

  f, err := os.Open(pluginFilePath)

        ...........................

}

El código tomaba la ruta comodín proporcionada por el usuario (web.Params(c.Req)["*"]) y ejecutaba un filepath.Clean directamente sobre ella, luego filepath.Join(plugin.PluginDir, requestedFile). Esto permitía que segmentos de tipo ..%2f..%2f..%2f..%2fetc/passwd “salieran” del directorio del plugin después de la unión de las rutas.

La corrección es ahora la siguiente:

func (hs *HTTPServer) getPluginAssets(c *models.ReqContext) {

  pluginID := web.Params(c.Req)[":pluginId"]

  plugin, exists := hs.pluginStore.Plugin(c.Req.Context(), pluginID)

  if (!exists) {

    c.JsonApiErr(404, "Plugin not found", nil)

    return

  }

  // 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(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)

  f, err := os.Open(pluginFilePath)

        ...........................

}

Recomendaciones

  1. Aplicar el parche inmediatamente: Actualizar todas las instancias de Grafana comprendidas entre las versiones v8.0.0-beta1 y v8.3.0 a la versión más reciente.

  2. Proxy inverso: Si no es posible actualizar, utilizar un proxy inverso frente a Grafana que normalice la RUTA (PATH) de la solicitud para mitigar la vulnerabilidad.

  3. Monitorización y análisis: Realizar una auditoría de los accesos y revisar las solicitudes al endpoint /public/plugins/ en busca de anomalías.

  4. Defensa en profundidad: Utilizar un Web Application Firewall (WAF) configurado para bloquear los intentos de recorrido de ruta (path traversal) como una capa adicional de protección.

[Callforaction-THREAT-Footer]