10 Oct 2026 · security, senhas, infrastructure · 4 min
123456 opened 8.8 million Danish records
The administrator account at the company with access to Denmark’s civil register used the password 123456. It was not alone: at least three accounts at Pays, a small company on the island of Funen, logged in with the same password to the system holding the name, address and personal number of practically every Dane, living or dead.
That account had legitimate access. That detail is what makes the case worth more than the joke about the password. Danish private companies may query the CPR, the central person register, when they have a legal basis and identify who they are asking about. The intruder broke no cryptography, cracked no hash and leaked no database: they used credentials from someone already authorized. According to Politiken’s reporting, the intruder said they used that password to reach 5.5 million records of living people and 3.3 million of dead ones.
The register holds about 11 million people, including the deceased and those who emigrated. People who requested name and address protection were not part of the exposure, per the CPR administration. The irregular activity ran through September, and the administration noticed on the evening of October 2. The company’s access was cut, the data protection authority was notified, and the police are investigating.
The hash arithmetic, measured
It is worth measuring what a weak password actually costs, because the answer swings hard with what the attacker holds. I ran the hash functions on one CPU core and projected the time for a list of 10 thousand common passwords and for 100 million attempts:
| scheme | time per attempt | attempts per second | 10k passwords | 100 million |
|---|---|---|---|---|
| MD5 | 0.0005 ms | 1,826,510 | 0.005 s | 55 s |
| SHA-1 | 0.0005 ms | 1,825,296 | 0.005 s | 55 s |
| SHA-256 | 0.0006 ms | 1,605,404 | 0.006 s | 1 min |
| SHA-512 | 0.0007 ms | 1,456,672 | 0.007 s | 1.1 min |
| PBKDF2-SHA256, 600k iterations | 0.240 s | 4 | 40 min | 278 days |
| scrypt, n=2^15, 32 MB | 0.087 s | 12 | 14.5 min | 100 days |
The gap between the first row and the last is close to half a million times. A 10 thousand entry list finishes in 5 thousandths of a second under MD5 and in 40 minutes under PBKDF2. Peak process memory was 45 MB.
And the full list never gets used here, because the first guess wins. 123456 sits at the top of the public most-used-password lists for both 2025 and 2026, with over 21 million occurrences in NordPass counting, per the Wikipedia list. Anyone building a wordlist starts exactly there.
import hashlib, time
password = b"123456"
salt = bytes(range(16))
t0 = time.perf_counter()
for _ in range(10000):
hashlib.md5(password).hexdigest()
print("MD5: %.4f s for 10k attempts" % (time.perf_counter() - t0))
t0 = time.perf_counter()
hashlib.pbkdf2_hmac("sha256", password, salt, 600000)
print("PBKDF2 600k: %.3f s per attempt" % (time.perf_counter() - t0))
What would have helped
Not hashing. The hash protects a stolen database, and a slow KDF remains the right choice for user passwords, but it has nothing to do with an attacker who logs in. The door was open and the lock was fine.
Counting would have helped. If September’s extraction ran across the thirty days of the month, 8.8 million queries come to 3.4 per second, without pause, overnight and on Sunday. That is a pace a script sustains and an employee does not. A volume alert, a per-credential limit and a warning when queries leave the company’s normal hours cost less than the strong password nobody used.
The second lesson is about aggregation. A credential that legitimately queries millions of records is, by design, an insider risk. The fix is to treat that access as privileged: second factor, secret rotation, logging every query and a periodic review of who needs that volume.
Caveat: the hash measurement is one CPU core, no GPU, projected from the cost of a single attempt. A graphics card makes MD5 and SHA orders of magnitude faster and makes PBKDF2 and scrypt far less competitive.
My read is that this case becomes a training slide, and the slide hides the point. The stupid password is the symptom. The system that let a stupid password extract a whole country for a month is the problem. The password is the cheapest control to audit and the one that decides the least, and it always shows up when the part that breaks is not the part that looked fragile. For the same reasoning seen from outside, with numbers the owner did not have, there is the case of outside measurements of a model.