User tests: Successful: Unsuccessful:
Pull Request resolves # .
Totp::checkCode() matched the generated one-time passcode against the submitted value with a loose ==. getCode() returns a zero-padded numeric string, so PHP numeric juggling makes non-codes compare equal ("012345" == 12345, "123456" == "+123456", "123456" == " 123456"), and the comparison is not constant time. Switched to hash_equals() with a string cast. The TOTP setup handler read the code with getInt('code'), which drops leading zeros before it ever reaches the check; it now uses getCmd('code'), the same as the email MFA plugin and the captive login path, so the strict comparison keeps working for codes that start with 0. The fixed MFA plugin already uses hash_equals; this aligns the TOTP path with it.
+ (for example +123456).Unit test: tests/Unit/Libraries/Cms/Encrypt/TotpTest.php.
+123456 (and other numeric-juggling variants of the current code) is accepted as a valid code.
Only the exact current code is accepted; juggling variants are rejected, and codes with a leading zero still validate.
Please select:
Documentation link for guide.joomla.org:
No documentation changes for guide.joomla.org needed
Pull Request link for manual.joomla.org:
No documentation changes for manual.joomla.org needed
| Status | New | ⇒ | Pending |
| Category | ⇒ | Libraries Front End Plugins Unit Tests |
| Title |
|
||||||
Sorry about that, ticked the box. Will make sure it's checked on future PRs.
| Labels |
Added:
Unit/System Tests
PR-5.4-dev
|
||
I cannot reproduce the issue. On each Login form , both front end and back end,
I cannot reproduce the issue. On each Login form , both front end and back end,
Thanks for testing. The separate code page is the captive login step, that's expected.
The reason the browser won't let you submit +123456 is that the code field carries pattern="[0-9]{6}" and maxlength="6" (the input_attributes in the totp plugin), so HTML5 validation blocks it before anything is sent. That check is client-side only though, and it isn't what the server relies on. Remove those two attributes in devtools, or post the login/setup request directly, and the raw value reaches the server. On the current code checkCode() compares with a loose == against a zero-padded numeric string, so +123456, 123456, 0012345 and similar juggle equal and are accepted. With the patch only the exact code passes.
If it's easier to see without a browser, the unit test in the PR covers it: testCheckCodeRejectsTypeJuggledPasscode fails on the old == and passes with hash_equals.
I have tested this item ✅ successfully on a797ac0
At first, I was not able to reproduce the issue. But following @arib06 comment, I removed some checks from the page's HTML code. After that, the issue could be reproduced, and I was able to successfully complete the MFA login with a seven-digit code like ' nnnnnn' or '+nnnnnn'.
After applying the patch, I did the identical manipulation to the page's HTML code, but the previously successful entries didn't work anymore.
I have tested this item ✅ successfully on a797ac0
At first, I was not able to reproduce the issue. But following @arib06 comment, I removed some checks from the page's HTML code. After that, the issue could be reproduced, and I was able to successfully complete the MFA login with a seven-digit code like ' nnnnnn' or '+nnnnnn'.
After applying the patch, I did the identical manipulation to the page's HTML code, but the previously successful entries didn't work anymore.
I have tested this item ✅ successfully on a797ac0
At first, I was not able to reproduce the issue. But following @arib06's comment, I removed some checks from the page's HTML code. After that, the issue could be reproduced, and I was able to successfully complete the MFA login with a seven-digit code like ' nnnnnn' or '+nnnnnn'.
After applying the patch, I did the identical manipulation to the page's HTML code, but the previously successful entries didn't work anymore.
| Labels |
Added:
PBF
|
||
I have tested this item ✅ successfully on d36ba75
I have tested this item ✅ successfully on d36ba75
| Status | Pending | ⇒ | Ready to Commit |
RTC
RTC
| Labels |
Added:
RTC
Removed: PBF |
||
✅ Final test before merge with JBT and macOS Safari
pattern="[0-9]{6}" maxlength="6" in HTML code| Status | Ready to Commit | ⇒ | Fixed in Code Base |
| Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2026-08-28 06:58:05 |
| Closed_By | ⇒ | muhme |
@arib06 Do we have to tell you for each of your PRs that you shall check the check box that you have read the AI policy? I did that already for your other PR and have to do the same again now.