Chat on WhatsApp
Magento glossary

What is the Magento crypt-key ?

The Magento crypt-key is a 256-bit symmetric AES key stored at app/etc/env.php under crypt.key. Magento’s Encryptor uses it to encrypt sensitive data at rest — saved-payment tokens in Magento_Vault, OAuth and REST API tokens, integration secrets, and any config field flagged with backend_model="...\Backend\Encrypted". Cipher is AES-256-CBC (2.0+) or AES-256-GCM (2.4.6+). Rotate via bin/magento encryption:key:change. Treat the crypt-key as a top-tier secret — lose it and every saved token, every API credential, every encrypted config field is gone.

How it works

Five steps from key generation to rotation in production

The crypt-key is not magic — it is a 32-byte hex string and a documented call path. Here is the wiring, end to end.

  1. 01

    Magento installer generates a 256-bit key

    At first install (bin/magento setup:install ...), a random 32-byte hex key is generated by Magento’s installer and written to app/etc/env.php under 'crypt' => ['key' => '<hex>']. The same key is stored in a fallback array structure — crypt.key becomes a multi-entry array as soon as rotations happen, with the oldest key first and the newest key last. The hex length is exactly 64 characters (32 bytes × 2 hex chars), equal to the AES-256 key length.

  2. 02

    Application code encrypts on write

    When Magento_Vault saves a payment-method token, the framework’s EncryptorInterface::encrypt() is called. It picks the newest key in the crypt.key array, runs AES-256-CBC or AES-256-GCM with a random IV, base64-encodes the result, prepends a key-version marker (0_:, 1_:, etc.) so the framework knows which key encrypted that row, and writes the ciphertext into the DB column. The same path runs for OAuth tokens, integration secrets, and encrypted core_config_data rows.

  3. 03

    Application code decrypts on read

    Encryptor::decrypt() reads the version marker on the ciphertext (0_:, 1_:, ...), looks up the corresponding key in the crypt.key array, and runs AES decryption with the matching cipher. If the key for that version is missing from env.php — because someone restored an old DB dump onto a new env, or trimmed the array thinking the old key was unused — the decrypt throws and the encrypted value is permanently unrecoverable. The version marker is the only reason multi-key rotation can work without re-encrypting the whole DB instantly.

  4. 04

    Rotation via bin/magento encryption:key:change

    The CLI command bin/magento encryption:key:change generates a new key, appends it to the crypt.key array (so the array now has both old and new), then walks every encrypted column in the database — vault_payment_token, oauth_token, integration, encrypted rows in core_config_data, plus any third-party encrypted columns — and re-encrypts each row with the new key, updating the version marker. The old key is kept in the array so that historic backups and any rows the walker missed can still decrypt.

  5. 05

    Secrets management — never commit env.php

    app/etc/env.php is in .gitignore by default for a reason — it holds the crypt-key, the DB password, the admin frontname, and the session cookie config. Production deployment loads env.php from a secrets manager (AWS Secrets Manager, HashiCorp Vault, Cloudflare Secrets, sealed Kubernetes secrets) at runtime, never baked into a container image. Always back up the crypt-key out of band in an encrypted password manager — losing the env.php on a server with no backup of the crypt-key loses every saved payment token, every API credential, and every encrypted config field.

When to rotate

Four moments when rotating the crypt-key is the obvious move

Rotation is cheap with the right runbook. These are the moments where the cost of running on an inherited or possibly-leaked key dominates the cost of rotating.

  • On first Magento install — verify the key is strong

    Right after bin/magento setup:install, open app/etc/env.php and confirm the crypt.key value is a long random 64-character hex string — not a recognisable placeholder, not a short ASCII phrase, not blank. Some older Adobe Commerce Cloud base images defaulted to a known-weak key, and some third-party install scripts have shipped predictable defaults. If the key looks short, predictable, or matches anything documented in a Magento Security Bulletin, rotate immediately with bin/magento encryption:key:change before the store sees its first real saved-payment-token.

  • After personnel change or suspected env.php leak

    Any developer or contractor who has ever had read access to app/etc/env.php holds the crypt-key in their head, their laptop, or their backup archives. The moment one of them rolls off the project, or a laptop gets lost, or an env.php gets accidentally pasted into a Slack DM, the right action is to rotate immediately via bin/magento encryption:key:change. The rotation is non-disruptive in maintenance mode and invalidates the old key for any future ciphertext. Do not wait for an incident — rotate at the personnel-change milestone.

  • After a Magento upgrade that changes the cipher

    Magento 2.4.6 introduced AES-256-GCM as the new default cipher, alongside the legacy AES-256-CBC. Existing ciphertext stays decryptable with the old cipher because the version marker carries the cipher hint, but rotating the crypt-key after the upgrade also re-encrypts every column to the new AES-GCM cipher in one pass. GCM offers authenticated encryption (catches tampering at decrypt time), which CBC does not — so on any security-sensitive store, schedule a key rotation right after the 2.4.6+ upgrade as a cipher upgrade too.

  • After a breach or PCI-DSS incident

    If a server is compromised, a backup is exfiltrated, or a PCI auditor flags a leaked credential, key rotation is the only way to invalidate every old encrypted token in one move without scanning every encrypted column by hand. bin/magento encryption:key:change re-encrypts everything with a brand-new key, so any ciphertext copied out before the rotation can no longer be decrypted with the new env.php even if the old env.php leaks again later. Combine with a forced password reset for all admin users and a vault-token purge for every saved payment.

Common mistakes

Three crypt-key mistakes that wreck a Magento store

Every crypt-key emergency I’ve been called in to triage came from one of these three mistakes. Audit your repo, your backup pipeline, and your rotation runbook before you need them.

  • Committing env.php to git

    The single most common Magento security leak. app/etc/env.php holds the crypt-key, the DB password, the admin frontname, and the session config — one accidental git add app/etc and the whole site is exposed in the git history forever, even after a delete commit. Always confirm env.php is listed in .gitignore (it is, by default, in fresh installs — but custom .gitignore rewrites often miss it). Commit a sample env.php.example only. If you discover env.php in git history, ROTATE the crypt-key immediately and rewrite the git history with git filter-repo.

  • Restoring a DB dump without the matching crypt.key

    When you copy a production DB dump down to staging, the ciphertext in vault_payment_token, oauth_token, and encrypted rows of core_config_data all expect to be decrypted with the production crypt-key. Restoring the dump onto a fresh Magento install with its own auto-generated crypt-key turns every encrypted column into garbage — saved-payment-tokens silently fail at checkout, API integrations 401, and encrypted config fields decrypt to noise. The crypt-key MUST travel alongside any DB dump. If you forgot, the only fix is to clear vault_payment_token, regenerate API integrations, and re-enter every encrypted config value via admin.

  • Running encryption:key:change on a live store without maintenance mode

    The rotation walks every encrypted column in the database and can take several minutes on a large store. Any concurrent vault-token-save or admin config-save during that walk can end up encrypted with one key but pointing at another via the version marker, leaving permanently-broken rows that no key in env.php can decrypt. Always wrap the rotation in bin/magento maintenance:enable first, run the rotation, verify a few decrypts work, then maintenance:disable. On a CI/CD pipeline this is a release-window job, not a hot-fix.

FAQ

Magento crypt-key — frequently asked questions

  • Can I change the crypt-key manually by editing env.php?
    No — never. The crypt-key in env.php is the symmetric key Magento uses to decrypt every encrypted DB column (saved-payment-tokens, OAuth tokens, integration secrets, encrypted core_config_data rows). If you swap the value in env.php without re-encrypting the DB, every existing ciphertext becomes permanently undecryptable — the version marker on each ciphertext (0_:, 1_:) points at a key index that no longer matches the actual value. The correct path is always bin/magento maintenance:enable followed by bin/magento encryption:key:change, which atomically generates the new key, walks every encrypted column, and re-encrypts each row with the new key while keeping the old key in the array as a fallback.
  • What happens if I’ve lost the original crypt-key?
    Every saved payment token, OAuth/API credential, and encrypted config field that was encrypted with the lost key is permanently unrecoverable — AES-256 is unbreakable in practice without the key. The practical recovery path is: 1) clear vault_payment_token (customers will re-enter cards on next checkout), 2) regenerate every API integration in admin (Stores → Integrations) so external systems re-pair, 3) re-enter every encrypted config field manually in admin (payment-gateway credentials, SMTP passwords, third-party API keys flagged with backend_model="Magento\Config\Model\Config\Backend\Encrypted"). Then generate a fresh strong crypt-key by running bin/magento encryption:key:change — even though there’s nothing left to re-encrypt, the command writes the new key cleanly. Document the new key in your password manager immediately.
  • Does the crypt-key rotation require downtime?
    For any production store, yes — always run in maintenance mode. bin/magento encryption:key:change walks every encrypted column in the database, and on a large store with hundreds of thousands of saved-payment-tokens or many encrypted config rows the walk can take several minutes. Any concurrent write during the walk — a customer saving a new card, an admin saving a config field, an API call provisioning a token — can end up encrypted with one key but with a version marker pointing at another, leaving a permanently-broken row. The safe sequence is: bin/magento maintenance:enable, then the rotation, then a spot-check decrypt on a sample of the rotated rows, then maintenance:disable. Schedule it inside a release window, not as a hot-fix.
  • How long should the crypt-key be?
    Magento generates a 256-bit (32-byte) key by default, encoded as 64 hex characters — equal to the AES-256 key length. Do not shorten it. Do not replace it with an ASCII phrase. Do not derive it from anything memorable. The right way to generate a replacement value — if you ever need to seed one before encryption:key:change rebuilds it — is openssl rand -hex 32, which produces exactly the 64-hex-char format Magento expects. AES-256 with a properly random 256-bit key has no known practical attack; the only way the encryption becomes weak is if the key itself is short, predictable, or leaked.
  • Is the crypt-key the same as Magento’s password hash salt?
    No — completely separate systems. Customer and admin passwords are hashed with a one-way function (bcrypt or argon2 in modern Magento) using a per-row random salt that is stored in the same column as the hash. That hash is one-way: Magento can verify a password at login by re-hashing the input, but it cannot reverse the hash to retrieve the original password — the crypt-key is not involved at all. The crypt-key, by contrast, is for two-way encryption of secrets the application needs to read back and use — payment-method tokens get re-sent to the PSP, API credentials get re-sent to third-party systems, encrypted config values get decrypted at runtime. Rotating the crypt-key does not invalidate any password; rotating passwords does not affect the crypt-key.
  • How do I check if my crypt-key is the Adobe Commerce Cloud default weak key?
    Open app/etc/env.php and copy the value of crypt.key. Compare against any known-bad hashes documented in the relevant Magento Security Bulletin (Adobe publishes these at helpx.adobe.com/security). If it matches a published weak key, rotate immediately. As a defence-in-depth measure even if it does not match, on any store inherited from a previous developer or a managed-hosting provider, just rotate — bin/magento maintenance:enable && bin/magento encryption:key:change && bin/magento maintenance:disable. The rotation is cheap, the cost of running on a leaked key is potentially catastrophic. Pair the rotation with rotating the DB password and admin passwords for full key-hygiene on the inherited install.
Crypt-key audit

Want a crypt-key + env.php audit on your Magento store?

Send your storefront URL — I will check your env.php hygiene, crypt-key strength, rotation history, encrypted-column health, and backup-of-key procedure, then reply with a written hardening plan, fixed-price quote, and earliest start date. 24-business-hour turnaround.