{"record":{"id":"8eca169cd50e9c5e","repo":"apereo/cas","slug":"secret-key-for-encryption-is-undefined-under","errorCode":null,"errorMessage":"Secret key for encryption is undefined under [{}]. CAS will attempt to auto-generate the encryption key","messagePattern":"Secret key for encryption is undefined under \\[(.+?)\\]\\. CAS will attempt to auto-generate the encryption key","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/cas-server-core-util-api/src/main/java/org/apereo/cas/util/cipher/BaseBinaryCipherExecutor.java","lineNumber":163,"sourceCode":"\n    private byte[] decodeWithPrefixedInitializationVector(final byte[] value) throws Exception {\n        val iv = Arrays.copyOfRange(value, 0, GCM_IV_LENGTH);\n        val encrypted = Arrays.copyOfRange(value, GCM_IV_LENGTH, value.length);\n        val aesCipher = Cipher.getInstance(CIPHER_ALGORITHM);\n        aesCipher.init(Cipher.DECRYPT_MODE, this.encryptionKey, new GCMParameterSpec(GCM_TAG_LENGTH, iv));\n        return aesCipher.doFinal(encrypted);\n    }\n\n    private byte[] decodeWithLegacyParameterSpec(final byte[] value) throws Exception {\n        val aesCipher = Cipher.getInstance(CIPHER_ALGORITHM);\n        aesCipher.init(Cipher.DECRYPT_MODE, this.encryptionKey, this.parameterSpec);\n        return aesCipher.doFinal(value);\n    }\n\n    private void ensureEncryptionKeyExists(final String encryptionSecretKey, final int encryptionKeySize) {\n        final byte[] genEncryptionKey;\n        if (StringUtils.isBlank(encryptionSecretKey)) {\n            LOGGER.warn(\"Secret key for encryption is undefined under [{}]. CAS will attempt to auto-generate the encryption key\", getEncryptionKeySetting());\n\n            if (encryptionKeySize <= MINIMUM_ENCRYPTION_KEY_LENGTH) {\n                val key = new Base64RandomStringGenerator(encryptionKeySize).getNewString();\n                val prop = String.format(\"%s=%s\", getEncryptionKeySetting(), key);\n                issueWarningToAddKeyToSettings(\"encryption\", encryptionKeySize, key, prop);\n                genEncryptionKey = EncodingUtils.decodeBase64(key);\n            } else {\n                val keyGenerator = FunctionUtils.doUnchecked(() -> KeyGenerator.getInstance(this.secretKeyAlgorithm));\n                keyGenerator.init(encryptionKeySize);\n                val secretKey = keyGenerator.generateKey();\n                genEncryptionKey = secretKey.getEncoded();\n                val encodedKey = EncodingUtils.encodeBase64(genEncryptionKey);\n                val prop = String.format(\"%s=%s\", getEncryptionKeySetting(), encodedKey);\n                issueWarningToAddKeyToSettings(\"encryption\", encryptionKeySize, encodedKey, prop);\n            }\n        } else if (encryptionKeySize <= MINIMUM_ENCRYPTION_KEY_LENGTH) {\n            val base64 = EncodingUtils.isBase64(encryptionSecretKey);\n            val key = base64 ? EncodingUtils.decodeBase64(encryptionSecretKey) : ArrayUtils.EMPTY_BYTE_ARRAY;","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-util-api/src/main/java/org/apereo/cas/util/cipher/BaseBinaryCipherExecutor.java#L145-L181","documentation":"Warning logged by BaseBinaryCipherExecutor.ensureEncryptionKeyExists when the configured encryption secret key setting is blank. CAS then auto-generates a random key at runtime and warns that the key MUST be added to configuration; without persisting it, keys are regenerated on each restart.","triggerScenarios":"Starting CAS with a cipher executor (tickets, OAuth/OIDC tokens, webflow crypto, etc.) whose cas.* encryption key property (e.g. cas.ticket.crypto.encryption.key) is unset or empty.","commonSituations":"Fresh CAS install with crypto enabled but keys not generated yet; keys lost after switching deployments; enabling per-service or per-feature crypto without running the documented keygen step.","solutions":["Generate a Base64 key of the required size (e.g. via CasConfigurationUtils/KeyGenerator or 'java -jar cas-server* --generate-key') and set it in the corresponding cas.*.encryption.key property.","Copy the generated key from the warning log line into application.properties/yml so it persists across restarts.","If crypto is not needed, disable the cipher executor feature rather than leaving the key blank."],"exampleFix":"// before (application.properties)\ncas.ticket.crypto.enabled=true\n// after\ncas.ticket.crypto.enabled=true\ncas.ticket.crypto.encryption.key=ZXhhbXBsZS1iYXNlNjQtZW5jb2RlZC1rZXktMTI4LWJpdHM=","handlingStrategy":"validation","validationCode":"String key = casProperties.getTicket().getCrypto().getEncryption().getKey();\nif (key == null || key.isBlank()) {\n    throw new IllegalStateException(\"Encryption key must be set in cas.ticket.crypto.encryption.key before startup\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run CAS keygen and commit generated keys to config/secrets before first deployment.","Add a startup smoke check that all enabled crypto features have non-blank keys.","Keep keys in a vault injected via environment, not generated ad hoc."],"tags":["encryption","missing-config","keys"],"backgroundTag":"missing-config-value","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}