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.
- Location app/etc/env.php, crypt.key array (hex)
- Cipher AES-256-CBC (2.0+) or AES-256-GCM (2.4.6+)
- Rotate via bin/magento encryption:key:change
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.
01Magento 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.
02Application 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.
03Application 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.
04Rotation 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.
05Secrets 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.
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.
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.
Where the crypt-key sits in the wider Magento security stack
Five neighbour concepts most readers want to look at next. Click through for the full deep-dive.
- What is Magento env.phpThe file that holds the crypt-key, plus the DB credentials, admin frontname, and session config. Never commit it, treat as the highest-value secret in the codebase.
- What is Magento PCI complianceCrypt-key compromise equals saved-payment-token compromise equals PCI incident. Compliance frames why rotation cadence and out-of-band backup matter.
- Magento upgrade serviceCipher upgrades (2.4.6 brought AES-256-GCM as the new default) happen during version upgrades. Key-rotation as part of the upgrade is a free security win.
- Magento extension developmentCustom modules adding encrypted config fields via backend_model="...\Backend\Encrypted" use the crypt-key transparently, build them right the first time.
- Hire a Magento developerAdobe Certified Magento & Hyvä developer, ten years on platform. Crypt-key audits, env.php hardening, rotation playbooks, fixed-price or hourly.
Magento crypt-key: frequently asked questions
Can I change the crypt-key manually by editing env.php?
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?
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?
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?
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?
How do I check if my crypt-key is the Adobe Commerce Cloud default weak key?
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.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.