Description
A password composed entirely of characters outside the Base64 alphabet (A–Z, a–z, 0–9, +, /) is silently reduced to an empty string by cleanPassword(), which makes encode() apply a shift of 0 to every codon. The result is byte-for-byte identical to encoding with no password at all. A user who deliberately chooses a password like !@#$% believes their message is encrypted when it is not, and receives no warning.
Steps to reproduce
- Enter
secret in Plaintext.
- Enter
!@#$% in the Password field.
- Click Encode ➜.
- Ciphertext =
CTATCGCCCGATCTAGCGCCCTCA.
- Clear the Password field and click Encode ➜ again.
- Ciphertext =
CTATCGCCCGATCTAGCGCCCTCA — identical.
Expected: a non-empty password produces ciphertext distinct from the no-password output (or the user is told the password was rejected).
Actual: the two ciphertexts are identical; the password had no effect and no warning was shown.
Conditions
Occurs whenever every character of the password is stripped by PASSWORD_REGEX — i.e. the password contains no A–Z, a–z, 0–9, +, or /. Passwords with at least one valid character are only partially affected: their invalid characters are silently dropped, so e.g. k!e!y encrypts as key, which is a weaker but less visible variant of the same problem.
Impact
Medium (security). The tool presents password-based encryption as a feature, so a silently-ignored password is a confidentiality failure: the user ships what they think is protected ciphertext but is actually the unprotected default encoding. The partial-stripping case also means two different passwords can silently map to the same key.
Root cause
site/js/codon64.js:
const PASSWORD_REGEX = /[^A-Za-z\d\/+]/g;
function cleanPassword(password) {
return password.replaceAll(PASSWORD_REGEX, '')
}
and in getShift():
if (password === '') {
return 0;
}
cleanPassword('!@#$%') returns '', so getShift() takes the no-password branch and returns shift 0 for every codon. The stripping is silent — there is no signal that characters were removed or that the effective password is empty.
Proposed fix
Surface the condition instead of silently degrading. At minimum, when the raw password is non-empty but cleanPassword() returns '', warn the user that the password contained no usable characters and was ignored. Optionally, widen the accepted alphabet or map arbitrary characters into the shift space so that any non-empty password contributes to the key rather than being discarded.
A minimal UI-level guard in site/js/home.js, at the encode/decode click handlers:
if (password.value !== '' && cleanPassword(password.value) === '') {
// e.g. highlight the field / show a message
console.warn('Password contained no usable characters and was ignored.');
}
This keeps the existing encoding behavior but removes the silent-no-encryption surprise.
Description
A password composed entirely of characters outside the Base64 alphabet (
A–Z,a–z,0–9,+,/) is silently reduced to an empty string bycleanPassword(), which makesencode()apply a shift of 0 to every codon. The result is byte-for-byte identical to encoding with no password at all. A user who deliberately chooses a password like!@#$%believes their message is encrypted when it is not, and receives no warning.Steps to reproduce
secretin Plaintext.!@#$%in the Password field.CTATCGCCCGATCTAGCGCCCTCA.CTATCGCCCGATCTAGCGCCCTCA— identical.Expected: a non-empty password produces ciphertext distinct from the no-password output (or the user is told the password was rejected).
Actual: the two ciphertexts are identical; the password had no effect and no warning was shown.
Conditions
Occurs whenever every character of the password is stripped by
PASSWORD_REGEX— i.e. the password contains noA–Z,a–z,0–9,+, or/. Passwords with at least one valid character are only partially affected: their invalid characters are silently dropped, so e.g.k!e!yencrypts askey, which is a weaker but less visible variant of the same problem.Impact
Medium (security). The tool presents password-based encryption as a feature, so a silently-ignored password is a confidentiality failure: the user ships what they think is protected ciphertext but is actually the unprotected default encoding. The partial-stripping case also means two different passwords can silently map to the same key.
Root cause
site/js/codon64.js:and in
getShift():cleanPassword('!@#$%')returns'', sogetShift()takes the no-password branch and returns shift 0 for every codon. The stripping is silent — there is no signal that characters were removed or that the effective password is empty.Proposed fix
Surface the condition instead of silently degrading. At minimum, when the raw password is non-empty but
cleanPassword()returns'', warn the user that the password contained no usable characters and was ignored. Optionally, widen the accepted alphabet or map arbitrary characters into the shift space so that any non-empty password contributes to the key rather than being discarded.A minimal UI-level guard in
site/js/home.js, at the encode/decode click handlers:This keeps the existing encoding behavior but removes the silent-no-encryption surprise.