Phalcon v5.20.3 / v6.0.0beta11 Released

Read time: 6 minutes
Phalcon v5.20.3 / v6.0.0beta11 Released

Phalcon v5.20.3 and v6.0.0beta11 have been released. This is a security-focused maintenance release.

TLDR

No, we did not skip a version. v5.20.2 was released on the 25th along with v6.0.0beta10. However, before we could post the article, we received emails at our security@phalcon.io address, about potential issues in several components. While those were being addressed, we also ran the framework code through Aikido, which also identified issues. The good news is that some of those had already been addressed, while others were genuine findings.

To that end, we worked to get all those issues fixed and the outcome is v5.20.3 and v6.0.0beta11.

Zephir

Additionally, Zephir has a minor version, so the framework has been compiled with 1.3.0

Note!

There are several areas that these AI tools flag as dangerous, and indeed some of them are, but there is always a balance between functionality, how much should the framework do, and what the developer is responsible for.

For example, our DataMapper component comes with a Profiler. If a developer enables the profiler and has it logging in a file, then the {values} parameter will inject all the passed parameters of every query logged into that logger. One might think that this is OK since it is the server’s local system, or even the local machine. Agreed on both; however, malicious actors do not care about that. If they find a door, they will walk right through it. So for the Profiler and other components, we ensured that there are visible callouts in the documentation to warn developers of the implications of using those components.

Thanks

We would like to extend a special thanks to Ilia Alshanetsky for his email security reports and Aikido for their service.

As always, thank you to everyone who reported an issue, opened a pull request, or tested a build before it shipped - and, this time, a particular thank you to everyone who sent a security report. Please keep looking; just send the next one to the address above.


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
  • The PHPUnit configuration now fails the run on notices, deprecations and PHPUnit deprecations, and prints the details of every triggering test.
  • Added regression tests for the hardening changes released in 5.20.0 and 5.20.1 that had no failing-on-revert coverage.

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.
  • Undefined index notice emitted for every literal route when Phalcon\Mvc\Router rebuilds its per-method index. #17527

Chat - Q&A

Support

Social Media

Videos

<3 Phalcon Team

Projects
We're a nonprofit organization that creates solutions for web developers. Our products are Phalcon, Zephir and others. If you would like to help us stay free and open, please consider supporting us.