Skip to content

Fix: Encryption ignores APP_KEY from env.toml and silently uses a public test key - #364

Merged
techmahedy merged 2 commits into
doppar:4.xfrom
abdulmajidcse:fix/encryption-app-key
Oct 12, 2026
Merged

techmahedy merged 2 commits into
doppar:4.xfrom
abdulmajidcse:fix/encryption-app-key

Conversation

@abdulmajidcse

@abdulmajidcse abdulmajidcse commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

Pull Request Checklist

Q A
Branch? 4.x
Bug fix? yes
New feature? no
Deprecations? no
Issues -
License MIT

Description

Encryption (behind Crypt, encrypt() and decrypt()) read the key only through getenv('APP_KEY'), and fell back to a hardcoded TESTING_KEY when that returned nothing. Application::loadTomlEnvironment() writes env.toml values only to $_ENV and $_SERVER and never calls putenv(), so getenv('APP_KEY') returned false for every app that sets its key in env.toml.

As a result, those apps encrypted everything with the TESTING_KEY published in this repository, with no error or warning, in every environment including production. Anyone could:

  • decrypt values encrypted with Crypt, such as encrypted model columns and 2FA secrets and recovery codes, from a database dump;
  • forge ciphertexts that decrypt() accepts, including remember-me cookie payloads and any app data passed through encrypt(). Remember-me logins are still blocked by the hashed token check against the database.

A missing or empty APP_KEY was handled the same silent way.

The fix:

  • reads the key the same way env() does ($_ENV, then $_SERVER, then getenv), so a key from env.toml is found;
  • throws a RuntimeException when APP_KEY is missing or empty, instead of falling back;
  • removes TESTING_KEY from the class. The test suite now gets its key from phpunit.xml.dist.

Upgrade note

Apps that loaded APP_KEY from env.toml have so far been encrypting with the public test key. After this change, data encrypted before the upgrade will not decrypt:

  • encrypted model columns will need re-encrypting;
  • users with 2FA will need to re-enroll;
  • remember-me cookies are dropped, and users log in again.

There is deliberately no automatic fallback to the old key, because that would keep accepting forged ciphertexts. This should be called out in the CHANGELOG / upgrade notes.

Flaky legacy decrypt (second commit)

The first CI run failed on Windows in test_decrypts_legacy_ciphertext_encrypted_with_pre_fix_buggy_key. The failure is not Windows-specific and was not caused by the change above. decryptLegacy() tried the correct key first and returned the first result that wasn't false. AES-256-CBC has no MAC, so the wrong key still "succeeds" whenever its garbage output happens to end in valid padding. With a random IV this happened in about 0.33% of runs (66 / 20000), and it affects real legacy data as well as the test.

decryptLegacy() now tries both keys and, when both decrypt, returns the result that is valid UTF-8, since wrong-key output is random bytes. A new test runs 3000 random IVs per key, so it reliably hits the ambiguous case. It fails on the old code and passes on the new.

Checklist

  • Tests have been added or updated (tests/EncryptionTest.php: 5 new tests. The env.toml-loaded key, missing-key, empty-key and legacy wrong-key tests fail on the old code.)
  • Documentation has been updated if necessary (the upgrade note above should go in the CHANGELOG)
  • Code follows the project coding standards
  • All tests pass locally (full suite and PHPStan)

@abdulmajidcse

Copy link
Copy Markdown
Member Author

I'm fixing issues...

@abdulmajidcse

Copy link
Copy Markdown
Member Author

@techmahedy now, check it.

@techmahedy

Copy link
Copy Markdown
Member

@abdulmajidcse thanks, I will check it, it was a genuine security related issue.

@techmahedy
techmahedy merged commit c32abb0 into doppar:4.x Oct 12, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants