1. Six CJK characters are worth only 30 bits
The sample password 密码强度评估 is a phrase I typed in off the top of my head, and my first instinct was that it must be far harder to guess than 8 random lowercase letters. The interface returned 30 bits, a score of 35 and the label "medium". On the same page zqxjvkwm came back with 37.6 bits and 43 points. The gap is not about length, it is about the charset: the charset declared on lines 126-131 of the template has only four addends, lowercase 26, uppercase 26, digits 10, and the negated character class /[^a-zA-Z0-9]/ on line 121 sweeps CJK characters, emoji and spaces all into the single bucket of 32.
So one CJK character is billed at log2(32)=5, exactly 5 bits. Extrapolate over the 3500 most common characters instead and 6 CJK characters should reach 70.6 bits, meaning the page undercounts by 40.6 bits.
Every figure quoted here was typed into the password strength checker one line at a time and copied off the readout. The tool also makes no network call and consults no leaked-password database: across the 285 lines of the template the tokens fetch, XMLHttpRequest, sendBeacon and localStorage each hit 0 times.
2. Length is billed in UTF-16 units
Line 134 reads pw.length, not the code point count. A single U+1F600 occupies 2 units and each unit is still worth 5 bits, so one emoji character shows 10 bits, 18 points and the label "weak", while 3 identical emoji add up to 6 units, 30 bits and 35 points. Emoji get no special treatment at all: the length merely doubles and picks up 5 extra bits, and the charset column still says 32.
The deduction is the more serious part. The repeated run detector on line 148 is written as (.)\1{2,}, and it fails on astral plane characters: 14 identical CJK characters and 7 identical emoji both come out at 70 bits, yet the first one loses 15 points and stops at 52, graded "medium", while the second keeps 67 and is graded "strong". One entropy value, two grades.
3. The dictionary has 27 entries and a hit only moves the score
The commonPasswords table on lines 103-108 holds 27 entries, the longest of them 10 characters. A hit costs 60 points, and isCommon on line 156 then forces the grade to "weak". The sharpest comparison: password and xqzmvkdt both measure 37.6 bits and both report 33 years in the online attack column, and the only difference between them is a score of 0 against 43. Matching the dictionary rewrites the score and the wording, while the entropy and the crack time do not change by a single number.
Line 123 performs nothing but an exact comparison after toLowerCase(), so changing one character drops you out of the table: PASSWORD still matches, whereas P@ssw0rd takes 77 points and password123456 takes 63 points, and both are labelled "strong".
4. The score caps at 70: entropy and grade are two separate lines
The grade only looks at score (lines 156-164): anything below 30 is "weak", 30 to 54 is "medium", 55 to 79 is "strong", and only 80 or above is "very strong". score itself is built on lines 140-152: a length term min(40, len*3), 10 points for each of the four character classes, an entropy term min(20, floor(entropy/4)), then minus 60 for a dictionary hit, minus 15 for a repeated run and minus 15 for a sequential run. A password that uses one class of characters has a ceiling of 40+10+20=70, so it can never reach 80.
| Password | Entropy bits | Score | Grade | Online attack column |
|---|---|---|---|---|
password (dictionary hit) | 37.6 | 0 | Weak | 33 years |
Zq8! (4 chars, all classes) | 26.2 | 58 | Strong | 4 days |
| 1008 lowercase characters | 4738 | 70 | Strong | age of the universe |
Zq8!Km4$vN2& (12 chars, all classes) | 78.7 | 95 | Very strong | 780,000 hundred million years |
A 240 digit numeric password likewise stops at 70 points, while the 26.2 bits of Zq8! in the table already counts as "strong" even though its online attack column is left with only 4 days.
5. The wording changes hundreds of orders of magnitude before the overflow
Line 201 computes half of the search space, 2^entropy/2, and divides it by the four hard-coded speeds on lines 195-200: online at 100 attempts per second, slow offline at 10,000 per second, fast offline at 10 billion per second, and GPU at 100 billion per second. The list page intro advertises "roughly 1 billion attempts per second on a normal CPU", yet the template has no tier for that number: measured on 37.6 bits, the third row shows 10 seconds rather than 2 minutes. The last three tiers are all offline speeds, and the order of magnitude between them is the subject of the note on how hashing algorithms differ in speed.
Genuine floating point overflow needs entropy to reach 1024 before Math.pow returns Infinity: the 94 character set needs 157 characters, the bucket of 32 (symbols share it with CJK characters) needs 205, and the bucket of 26 needs 218. Emoji units can only come in even numbers, so the bucket of 32 needs 206 units, that is 103 code points.
But formatTime on lines 249-263 answers both Infinity and 3.1536e+22 seconds with the same sentence, "age of the universe", because every comparison in its chain is false for Infinity and execution falls straight through to the last return. The 94 character set needs only 13 characters, 85.2 bits, before the online column already reads that way, and at that point the slow column still has 700,000 hundred million years left. The four columns switch their wording at lengths 13, 14, 17 and 18.
The unit chain keeps its own rounding quirks. The thresholds run in order: 0.001 seconds prints "instant", 1 second prints "< 1 second", then 60, 3600, 86400, 2592000 and 31536000, and past that the year tiers split at 1000, 1e6, 1e9, 1e12 and 1e15, always through Math.round. That is why 31535999 seconds prints "12 months", and why 31535999999999 seconds prints 1000 in the thousand year tier instead of 1 in the million year tier.
6. The two deduction tables disagree
The sequential character deduction table on line 150 carries 16 strings, while the improvement hints on line 223 test only 4 of them. Zxcde1!q contains both cde and def, so its score falls from 77 to 62, yet the suggestion box prints nothing except "increase password length to 12 characters or more" and never mentions sequential runs; Zsdf9!qq and Z890!qqA are silently docked 15 points the same way. The threshold for a repeated run is 3 characters or more: aaa at 14.1 bits is left with only 7 points, while aa keeps 18.
Length, by contrast, is wide open: the input on line 14 has no maxlength, so 1000 characters drawn from all four classes measure 6554.6 bits of entropy and score 100, and the median of 201 calls is 44.6 microseconds; even 20000 characters takes only 582.9 microseconds. There is no batch entry either, nothing is kept locally, and reloading returns you to 0 points and a bare dash. If you want something both long and messy, have the strong password generator produce a string first and then bring it here to be evaluated.
Q: can this page settle anything about CJK passwords?
No. What it reports is a bucket ceiling, so 6 CJK characters count as 30 bits while the extrapolation over the 3500 most common characters gives 70.6 bits. The grade is pulled around by the class bonus and by the two penalty tables, which means the same 70 bits can be printed as "medium" or as "strong". What really decides difficulty is how large the pool of characters in use is and what a credential stuffing run costs, and the template checks neither.
Q: should I stop once I see the age of the universe wording?
First work out which column is talking. The 94 character set needs only 13 characters, 85.2 bits, before the online attack column prints that sentence, and the slow column still has 700,000 hundred million years remaining at that moment; 2^entropy truly becomes Infinity only at 157 characters, and the two labels are identical word for word.
Q: should I follow the improvement hints literally?
Treat them as a reference rather than as an audit. They test only 4 sequential strings while the deduction table holds 16, and they never mention that CJK characters are folded into the bucket of 32 or that an emoji is billed as 2 units.