CVE-2026-54736: Phalcon Non-constant-time HMAC Verification Vulnerability

HIGH
Advisory Identifier: GHSA-8jqh-95g6-7jpj
CWE-208 CWE-347
Published
Advisory Summary

CVE-2026-54736 is a HIGH non-constant-time hmac verification vulnerability (CWE-208: Observable Timing Discrepancy) affecting Phalcon libraries in the Packagist ecosystem. The issue involves non-constant-time hmac verification in `encryption\crypt::decrypt` (timing side-channel). Remediation is available by upgrading affected packages to version 5.14.1.

CVE-2026-54736 at a Glance

CVE Identifier CVE-2026-54736
GHSA Identifier GHSA-8jqh-95g6-7jpj
Severity HIGH
CVSS v3.1 Base Score N/A
CWE Classification CWE-208: Observable Timing Discrepancy
Affected Product Phalcon
Package Ecosystem Packagist
Published Date
Last Updated

How to Fix CVE-2026-54736

To remediate this vulnerability, upgrade all affected Phalcon dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

phalcon/cphalcon fixed: 5.14.1
Upgrade phalcon/cphalcon to 5.14.1
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for phalcon/cphalcon

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-54736, inspect your project dependencies for Phalcon:

inspect dependencies for phalcon/cphalcon

Analyze the terminal output to locate any version of Phalcon in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 5.14.1), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-208: Observable Timing Discrepancy, where two separate operations in a product require different amounts of time to complete, in a way that is observable to an actor and reveals security-relevant information about the state of the product, such as whether a particular operation was successful or not. In Phalcon, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## 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): ```zephir 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`: ```c 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`: ```zephir // 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: - https://github.com/phalcon/cphalcon/issues/17090 Patched Stream: - https://github.com/phalcon/cphalcon/issues/17090

CVE-2026-54736 Affected Phalcon Versions

1 component(s)
Fixed Versions:
5.14.1
Product / Package Ecosystem Affected Versions Fixed Version
phalcon/cphalcon
Packagist
< 5.14.1
5.14.1

References

Frequently Asked Questions

What is CVE-2026-54736?
CVE-2026-54736 is a security vulnerability in Phalcon involving Non-constant-time HMAC verification in `Encryption\Crypt::decrypt` (timing side-channel) under CWE-208: Observable Timing Discrepancy.
Which Phalcon versions are affected?
Affected versions include releases prior to 5.14.1 across affected packages: phalcon/cphalcon.
What version fixes CVE-2026-54736?
Upgrading to 5.14.1 (or the latest patched release for your respective branch) resolves the vulnerability.
Is phalcon/cphalcon affected?
Yes, phalcon/cphalcon is affected in releases prior to 5.14.1. Upgrade your dependency to 5.14.1 or later.
What CWE is associated with CVE-2026-54736?
CVE-2026-54736 is classified under CWE-208: Observable Timing Discrepancy (Two separate operations in a product require different amounts of time to complete, in a way that is observable to an actor and reveals security-relevant information about the state of the product, such as whether a particular operation was successful or not.).
How can I check Packagist dependencies for CVE-2026-54736?
Run the dependency tree command: 'inspect dependencies for phalcon/cphalcon'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-8jqh-95g6-7jpj",
  "modified" : "2026-08-28T16:01:05Z",
  "published" : "2026-08-28T16:01:05Z",
  "aliases" : [ "CVE-2026-54736" ],
  "summary" : "Phalcon: Non-constant-time HMAC verification in `Encryption\\Crypt::decrypt` (timing side-channel)",
  "details" : "## Summary\n\n`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.\n\n## Details\n\n### Vulnerable code\n\n`phalcon/Encryption/Crypt.zep:246` (Zephir source):\n\n```zephir\nif true === this->useSigning {\n    // Checks on the decrypted message digest using the HMAC method.\n    if digest !== hash_hmac(hashAlgorithm, padded, decryptKey, true) {\n        throw new Mismatch(\"Hash does not match.\");\n    }\n}\n```\n\nGenerated C --> `ext/phalcon/encryption/crypt.zep.c:364-367`:\n\n```c\nZEPHIR_CALL_FUNCTION(&_8$$7, \"hash_hmac\", NULL, 245, &hashAlgorithm, &padded, &decryptKey, &__$true);\n...\nif (!ZEPHIR_IS_IDENTICAL(&digest, &_8$$7)) {                 // <-- non-constant-time\n    ZEPHIR_THROW_EXCEPTION_DEBUG_STR(..., \"Hash does not match.\", \"phalcon/Encryption/Crypt.zep\", 247);\n```\n\n`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).\n\n\n\n### Impact\n\nThe 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.\n\n## Suggested fix\n\nReplace the identity comparison with the constant-time helper already used elsewhere in the framework. In `phalcon/Encryption/Crypt.zep:246`:\n\n```zephir\n// before\nif digest !== hash_hmac(hashAlgorithm, padded, decryptKey, true) {\n    throw new Mismatch(\"Hash does not match.\");\n}\n// after\nif true !== hash_equals(hash_hmac(hashAlgorithm, padded, decryptKey, true), digest) {\n    throw new Mismatch(\"Hash does not match.\");\n}\n```\n\n`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`.\n\nAddressed Issue: \n\n- https://github.com/phalcon/cphalcon/issues/17090\n\nPatched Stream: \n\n- https://github.com/phalcon/cphalcon/issues/17090",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "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"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "phalcon/cphalcon"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "5.14.1"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 5.14.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/phalcon/cphalcon/security/advisories/GHSA-8jqh-95g6-7jpj"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-54736"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/phalcon/cphalcon/issues/17090"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/phalcon/cphalcon/pull/17091"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/phalcon/cphalcon/commit/ad53ab1b2e7ec59b3af92b0b37b8aaa099011137"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/phalcon/cphalcon"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/phalcon/cphalcon/releases/tag/v5.14.1"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-208", "CWE-347" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-08-28T16:01:05Z",
    "nvd_published_at" : "2026-07-10T22:16:42Z"
  }
}