isTaxID(dk-DK): valid CPR numbers wrongly rejected for century-digit 5-8, year 37-58
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- javascript
- Domain
- backend
Research direction
Start in src/lib/isTaxID.js at the dkDkCheck century_digit switch and review the existing year mapping for digits 5-8. Exercise isTaxID with the checksum-valid CPR examples in the issue, especially years 37-58, and confirm that the documented gap-free mapping accepts them while existing cases remain valid.
Written by the indexing model from the issue text.
Description
Description
isTaxID(str, 'dk-DK') (Danish CPR-nummer) incorrectly rejects syntactically- and checksum-valid CPR numbers whenever the 7th digit (century digit) is 5, 6, 7, or 8 and the 2-digit birth year is in the range 37-58 (inclusive).
Root cause
In src/lib/isTaxID.js, dkDkCheck:
switch (century_digit) {
case '0':
case '1':
case '2':
case '3':
year = `19${year}`;
break;
case '4':
case '9':
if (year < 37) {
year = `20${year}`;
} else {
year = `19${year}`;
}
break;
default: // century_digit is 5, 6, 7, or 8
if (year < 37) {
year = `20${year}`;
} else if (year > 58) {
year = `18${year}`;
} else {
return false;
}
break;
}
The case '4': case '9': branch correctly implements the documented rule for those digits (year 00-36 → 2000s, year 37-99 → 1900s).
For century digits 5, 6, 7, 8, the documented rule (see e.g. the century-digit table reproduced at https://blog.ploeh.dk/2018/12/10/danish-cpr-numbers-in-f/, sourced from the Danish Wikipedia CPR-nummer article) is a clean split with no gap: year 00-57 → 2000s, year 58-99 → 1800s.
The default branch instead reuses the wrong thresholds from the 4/9 case (year < 37 / year > 58), leaving years 37-58 falling into an else { return false; } that shouldn't exist at all — every 2-digit year should map to exactly one century for these digit values.
Reproduction (validator 13.15.35, latest on npm at time of writing)
Using checksum-valid constructed CPR numbers (day=01, month=01, century digit 5, correct check digit computed with the library's own weight formula):
const v = require('validator');
console.log(v.isTaxID('0101365018', 'dk-DK')); // true (year 36, correct)
console.log(v.isTaxID('0101375005', 'dk-DK')); // false <-- should be true (Jan 1 2037)
console.log(v.isTaxID('0101455009', 'dk-DK')); // false <-- should be true (Jan 1 2045)
console.log(v.isTaxID('0101575004', 'dk-DK')); // false <-- should be true (Jan 1 2057)
console.log(v.isTaxID('0101585018', 'dk-DK')); // false <-- should be true (Jan 1 1858)
console.log(v.isTaxID('0101595005', 'dk-DK')); // true (year 59, correct: Jan 1 1859)
Impact
Any application using isTaxID(input, 'dk-DK') will wrongly reject legitimate CPR numbers for:
- People born in 1858 (year=58 exactly — a case the CPR system explicitly supports; its historical documentation cites a real 1863 registrant, so 1858 is within the system's intended range) — affects historical-records validation today.
- Anyone issued a CPR number with a birth year of 2037-2057 under century digits 5-8 — will start affecting real newly-issued numbers as those years arrive.
This is a false-negative / over-rejection bug, not a validation bypass — no security impact, just incorrect application behavior for the affected date ranges.
Suggested fix
default: // century_digit is 5, 6, 7, or 8
if (year <= 57) {
year = `20${year}`;
} else {
year = `18${year}`;
}
break;
This matches the documented gap-free century-digit table for 5-8 and removes the erroneous rejection branch.
- Dominant language
- JavaScript
- Stars
- 23.7k
- Forks
- 2.5k
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from validatorjs/validator.js
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
validatorjs/validator.js#2885 ·
-
🐛 bug
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
validatorjs/validator.js#2862 ·
-
🐛 bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
validatorjs/validator.js#2861 ·
-
🐛 bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
validatorjs/validator.js#2860 ·
-
🐛 bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
validatorjs/validator.js#2859 ·
All issues in validatorjs/validator.js
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
HarperFast/skills#96 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Automattic/studio#4908 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
sugarlabs/musicblocks#8847 ·
-
client-controller-update ta-bot-triage team-money-movement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
MetaMask/metamask-mobile#36594 ·