GHSA-8jqh-95g6-7jpj

Suggest an improvement
Source
https://github.com/advisories/GHSA-8jqh-95g6-7jpj
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/08/GHSA-8jqh-95g6-7jpj/GHSA-8jqh-95g6-7jpj.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-8jqh-95g6-7jpj
Aliases
Published
2026-08-28T16:01:05Z
Modified
2026-08-28T16:15:06Z
Severity
  • 8.2 (High) CVSS_V4 - CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N CVSS Calculator
Summary
Phalcon: Non-constant-time HMAC verification in `Encryption\Crypt::decrypt` (timing side-channel)
Details

Summary

Phalcon\Encryption\Crypt provides authenticated encryption: when useSigning is enabled (the default), encrypt() appends an HMAC tag and decrypt() verifies it before returning the plaintext. The verification compares the attacker-supplied tag against the freshly computed HMAC using PHP/Zephir identity comparison (!==), which the Zephir compiler lowers to !ZEPHIR_IS_IDENTICAL(...) — a byte-wise memcmp that returns early on the first differing byte. The comparison time therefore depends on how many leading bytes of the supplied tag are correct, a classic MAC-verification timing side-channel. Every other secret/MAC comparison in the framework uses the constant-time hash_equals() (zephir_hash_equals) — the CSRF token check (Security::checkToken) and the JWT signature check (Signer\Hmac::verify); Crypt::decrypt is the lone deviation.

Details

Vulnerable code

phalcon/Encryption/Crypt.zep:246 (Zephir source):

if true === this->useSigning {
    // Checks on the decrypted message digest using the HMAC method.
    if digest !== hash_hmac(hashAlgorithm, padded, decryptKey, true) {
        throw new Mismatch("Hash does not match.");
    }
}

Generated C --> ext/phalcon/encryption/crypt.zep.c:364-367:

ZEPHIR_CALL_FUNCTION(&_8$$7, "hash_hmac", NULL, 245, &hashAlgorithm, &padded, &decryptKey, &__$true);
...
if (!ZEPHIR_IS_IDENTICAL(&digest, &_8$$7)) {                 // <-- non-constant-time
    ZEPHIR_THROW_EXCEPTION_DEBUG_STR(..., "Hash does not match.", "phalcon/Encryption/Crypt.zep", 247);

ZEPHIR_IS_IDENTICAL --> zephir_is_identical() (ext/kernel/operators.c:472) --> Zend is_identical_function --> for equal-length strings a memcmp that exits on the first mismatching byte (data-dependent timing).

Impact

The HMAC is the integrity/authentication tag of Phalcon's authenticated-encryption scheme. A successful timing attack (Keyczar/CVE-2009-0654-style: fix the IV+ciphertext so the target tag is constant, then recover it byte-by-byte from response timing) yields a tag the attacker can attach to a chosen IV+ciphertext so that decrypt() accepts it as authentic, defeating the integrity guarantee. Combined with CFB malleability (flipping a ciphertext byte flips the corresponding plaintext byte), an attacker who recovers the forging capability can tamper with the decrypted contents the application trusts (e.g. encrypted cookies carrying authorization/identity state). There is no confidentiality break by itself.

Suggested fix

Replace the identity comparison with the constant-time helper already used elsewhere in the framework. In phalcon/Encryption/Crypt.zep:246:

// before
if digest !== hash_hmac(hashAlgorithm, padded, decryptKey, true) {
    throw new Mismatch("Hash does not match.");
}
// after
if true !== hash_equals(hash_hmac(hashAlgorithm, padded, decryptKey, true), digest) {
    throw new Mismatch("Hash does not match.");
}

hash_equals() returns false for unequal-length inputs, so it also covers the truncated-tag case. Optional further hardening: verify the MAC before unpadding (functionally moot here because cryptUnpadText never throws) and consider migrating the default toward an AEAD mode such as aes-256-gcm.

Addressed Issue:

Patched Stream:

Database specific
{
    "cwe_ids":  [
        "CWE-208",
        "CWE-347"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-08-28T16:01:05Z",
    "nvd_published_at":  "2026-07-10T22:16:42Z",
    "severity":  "HIGH"
}
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.14.1

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
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.14.0"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/08/GHSA-8jqh-95g6-7jpj/GHSA-8jqh-95g6-7jpj.json"