{"record":{"id":"07abbb92df8ec0b5","repo":"jwtk/jjwt","slug":"password-has-been-destroyed-password-character-ar","errorCode":null,"errorMessage":"Password has been destroyed. Password character array may not be obtained.","messagePattern":"Password has been destroyed\\. Password character array may not be obtained\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/security/PasswordSpec.java","lineNumber":46,"sourceCode":"    private static final String ENCODED_DISABLED_MSG =\n            \"getEncoded() is disabled for Password instances as they are intended to be used \" +\n                    \"with key derivation algorithms only. Because passwords rarely have the length or entropy \" +\n                    \"necessary for secure cryptographic operations such as authenticated hashing or encryption, \" +\n                    \"they are disabled as direct inputs for these operations to help avoid accidental misuse; if \" +\n                    \"you see this exception message, it is likely that the associated Password instance is \" +\n                    \"being used incorrectly.\";\n\n    private volatile boolean destroyed;\n    private final char[] password;\n\n    public PasswordSpec(char[] password) {\n        Assert.notEmpty(password, \"Password character array cannot be null or empty.\");\n        this.password = password.clone(); // ensures changes to the source array do not change this instance\n    }\n\n    private void assertActive() {\n        if (destroyed) {\n            throw new IllegalStateException(DESTROYED_MSG);\n        }\n    }\n\n    @Override\n    public char[] toCharArray() {\n        assertActive();\n        return this.password.clone();\n    }\n\n    @Override\n    public String getAlgorithm() {\n        return NONE_ALGORITHM;\n    }\n\n    @Override\n    public String getFormat() {\n        return null; // encoding isn't supported, so we return null per the Key#getFormat() JavaDoc\n    }","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/security/PasswordSpec.java#L28-L64","documentation":"PasswordSpec implements Destroyable: after destroy() is called the internal char array is zeroed. Any subsequent call to toCharArray() (via assertActive()) throws IllegalStateException because the password is no longer usable or readable.","triggerScenarios":"Calling password.toCharArray() after password.destroy() has been invoked.","commonSituations":"Long-lived Password references destroyed by try-with-resources or security cleanup code, then accidentally reused later in the same request; caching a Password in a field and destroying it at logout.","solutions":["Do not reuse a Password after destroying it; create a new Password instance from the source credentials.","Restructure code so the char[] is consumed before destroy(), e.g. derive keys inside the usage scope.","Catch IllegalStateException around toCharArray() to detect destroyed credentials and fail gracefully."],"exampleFix":"// before\nPassword p = Keys.password(chars);\nderive(p); p.destroy();\nderive(p); // IllegalStateException\n// after\nPassword p = Keys.password(chars);\nderive(p); p.destroy();\n// re-create if needed\nPassword p2 = Keys.password(sourceChars);","handlingStrategy":"try-catch","validationCode":"if (password instanceof Destroyable d && d.isDestroyed()) {\n    throw new IllegalStateException(\"Password already destroyed\");\n}","typeGuard":"boolean usable(Password p) { return p instanceof Destroyable d && !d.isDestroyed(); }","tryCatchPattern":"try {\n    char[] chars = password.toCharArray();\n    // use chars\n} catch (IllegalStateException e) {\n    // password destroyed: recreate from source credentials\n}","preventionTips":["Treat destroy() as terminal — never reuse the instance","Scope Password usage tightly (try-with-resources)","Track destroyed credentials and recreate when needed"],"tags":["password","security","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}