github phalcon/cphalcon v5.20.3

2 hours ago

5.20.3 (2026-08-26)

Tools

  • Zephir 1.3.0

Changed

  • ACL role, component and access names can no longer contain !, the internal key delimiter; Phalcon\Acl\Exceptions\ForbiddenDelimiter is thrown instead.
  • Cache file names of Phalcon\Annotations\Adapter\Stream, Phalcon\Mvc\Model\MetaData\Stream and Phalcon\Storage\Adapter\Stream get a hash suffix when the key contains the character that the separator replacement produces (_ for class names; /, \, : for storage keys), so two different keys can no longer share one file. Names of all other keys are unchanged.
  • Phalcon\Auth\Guard\Session sets the Secure flag of the remember-me cookie from the new rememberSecure option (default true) instead of the request scheme, so a TLS-terminating proxy that reports plain HTTP to the backend cannot downgrade it.
  • Phalcon\Auth\Guard\Session validates the "remember me" token against the user agent of the current request instead of the one stored in the cookie; a browser user-agent change now ends a remembered session.
  • Phalcon\Encryption\Security::CRYPT_MD5, CRYPT_SHA256 and CRYPT_SHA512 are documented as weak legacy algorithms to be removed in a future major version; use bcrypt or Argon2 and rehash on login.
  • Phalcon\Storage\Adapter\Stream creates its shard directories with mode 0755 instead of 0777. Thanks to Ilia Alshanetsky

Added

  • Optional fifth argument stopOnFalse on Phalcon\Events\Manager::fire() (not on the interface), a per-call override of setStopOnFalse(); EventsAwareTrait::fireManagerEvent() gained a matching fourth argument.
  • Phalcon\Acl\Exceptions\ForbiddenDelimiter, thrown when an ACL role, component or access name contains !.
  • Phalcon\Auth\Exceptions\InvalidCredentialKey, thrown when a credential key passed to Phalcon\Auth\Adapter\Model::retrieveByCredentials() is not a plain identifier.
  • Phalcon\Http\Request\Bag\AbstractBag::clear(), removing all elements of a request bag.
  • allowedClasses option for the Storage adapters (true, false or a list of class names), forwarded to the new Phalcon\Storage\Serializer\Php::setAllowedClasses(): restricts the classes unserialize() may instantiate for stored values, including the nested content of the Stream adapter. A class outside the list makes the read fail instead of building an object. Thanks to Ilia Alshanetsky
  • rememberSecure option for the session guard (Phalcon\Auth\Guard\Config\SessionGuardConfig, Session::fromOptions()).

Fixed

  • "Remember me" cookie of another account surviving Phalcon\Auth\Guard\Session::logout() when the current user does not implement AuthRemember.
  • A false returned by a listener of acl:beforeCheckAccess, dispatch:beforeDispatch, dispatch:beforeExecuteRoute, micro:beforeHandleRoute or micro:beforeExecuteRoute being overwritten by a later listener that returned a non-null value; these boundaries now fire with stop-on-false, so a denial is final.
  • Asset output following a symbolic link at the target file and writing outside the assets directory.
  • Backslash path traversal in Phalcon\Mvc\View::partial() and Phalcon\Mvc\View\Simple::render() on Windows.
  • Cached user surviving Phalcon\Auth\Guard\Token::setRequest(), so a replaced request inherited the previous authentication.
  • Column comment concatenated unescaped into the CREATE TABLE / ALTER TABLE DDL of the MySQL dialect; it is now escaped like the DEFAULT clause. Thanks to Ilia Alshanetsky
  • Credential keys interpolated unvalidated into the PHQL built by Phalcon\Auth\Adapter\Model::retrieveByCredentials().
  • Distinct ACL tuples colliding on the same internal key when a role, component or access name contained !.
  • Fixed shared memory leak of response headers into other callers
  • JWT audience validated with a loose comparison, so a numeric or boolean aud claim satisfied a string audience.
  • Length-dependent HMAC work on the CBC decrypt failure path of Phalcon\Encryption\Crypt, which could still tell a padding failure from a MAC mismatch by timing.
  • Malformed ACL snapshot loaded by Phalcon\Acl\Adapter\Storage raising TypeError or leaving the adapter half loaded, and deep or cyclic object graphs recursing without limit; InvalidSnapshot is now thrown before any state changes.
  • Memory leak in the PHQL parser for every rejected literal when phalcon.orm.enable_literals is off.
  • Memory leak of the error message on every failed Phalcon\Mvc\Model\Query\Lang::parsePHQL() call (syntax and scanner errors); the string was only released at request shutdown.
  • Memory leak of the message buffer on every Volt syntax error (Phalcon\Mvc\View\Engine\Volt\Compiler); the buffer was only released at request shutdown.
  • Namespace middleware bypass in the ADR Router through case-variant or separator-injected paths that PHP resolves to the canonical Action class; only the exact declared class name is a match.
  • Non-string elements passed to Phalcon\Acl\Adapter\Memory::addInherit() raising a warning and a TypeError instead of InvalidRoleType.
  • Out-of-bounds read in the Annotations scanner when a docblock ends outside an annotation (for example @!); the scanner now stops at the end of the input and Reader::parseDocBlock() returns false instead of an unset value for a docblock without annotations.
  • Out-of-bounds read in the Annotations, Volt and PHQL scanners when a quoted string ends with a backslash: the escape rule could consume the string terminator.
  • Quadratic list building in the Annotations, Volt and PHQL parsers; argument lists, IN lists and array literals with tens of thousands of items now parse in linear time.
  • Request attributes of the previous route surviving on a reused request in Phalcon\ADR\Application::handle().
  • Scheme allow-list bypass in the Filter url sanitizer through HTML-entity obfuscated schemes (javascript:) and URLs that parse_url() cannot parse; the sanitizer now fails closed. Thanks to Ilia Alshanetsky
  • Validators Alpha, Alnum, Confirmation, CreditCard, Digit, Numericality, Regex, StringLength\Min and StringLength\Max cast an array value to the constant "Array", so field[]=x passed alphabetic, alphanumeric, length and confirmation checks; a value that cannot be a string is now rejected with the validator's message. Thanks to Ilia Alshanetsky
  • Volt extends-mode cache unserialized without a class restriction.
  • ReflectionException / TypeError from ACL rule callbacks with builtin-typed parameters, array callables or static-method strings.
  • acl:afterCheckAccess reporting the static rule instead of the final isAllowed() decision (rule callback and default action were not applied).
  • only() / except() action filters leaking between Phalcon\Auth\Manager::access() activations when the access gate was registered as a shared service in the legacy Di.

Removed

Don't miss a new cphalcon release

NewReleases is sending notifications on new releases.