The Medicare Beneficiary Identifier replaced the SSN-based HICN. Eleven characters in a fixed positional pattern of digits and a restricted letter set that excludes S, L, O, I, B and Z to avoid visual confusion.
// C = constrained letter set, N = digit, A = letter or digit
private static readonly Regex MbiPattern = new(
@"^[1-9][ACDEFGHJKMNPQRTUVWXY][ACDEFGHJKMNPQRTUVWXY0-9]\d" +
@"[ACDEFGHJKMNPQRTUVWXY][ACDEFGHJKMNPQRTUVWXY0-9]\d" +
@"[ACDEFGHJKMNPQRTUVWXY]{2}\d{2}$",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static bool IsMbiPlausible(string mbi) =>
MbiPattern.IsMatch(mbi.Replace("-", ""));Known-valid test value: 1EG4TE5MK73. The restricted alphabet does real work here. An eleven-character string matching this pattern by accident is unlikely, so despite having no checksum the MBI behaves closer to a validated identifier than the SSN does.
Verify the current pattern against CMS's published specification before relying on it.
For the entities with weak or absent checksums, proximity to a label does most of the work.
public static double ContextBoost(
string text, int matchStart, IReadOnlyList<string> cues, int window = 40)
{
var from = Math.Max(0, matchStart - window);
var span = text[from..matchStart].ToLowerInvariant();
return cues.Any(span.Contains) ? 0.35 : 0.0;
}Cue lists that earn their keep:
["ssn", "social security", "soc sec"]
["routing", "aba", "rtn", "wire"]
["account number", "acct", "checking", "savings"]
["npi", "provider id", "rendering provider"]
["ein", "tax id", "federal id", "fein"]
["mbi", "medicare", "beneficiary id"]
["mrn", "medical record", "chart number"]
["dl", "driver's license", "license number"]Not a detection spec. A list to check your entity coverage against, and a reminder that most of these have no pattern at all.
Names · geographic subdivisions smaller than a state · all date elements except year · telephone numbers · fax numbers · email addresses · Social Security numbers · medical record numbers · health plan beneficiary numbers · account numbers · certificate and licence numbers · vehicle identifiers and serial numbers including plates · device identifiers and serial numbers · web URLs · IP addresses · biometric identifiers including finger and voice prints · full-face photographs and comparable images · any other unique identifying number, characteristic, or code.
That last item is deliberately open-ended, and it is where your own internal customer reference belongs.
Removing all eighteen meets the Safe Harbor standard and does not eliminate re-identification risk from combinations of what remains, which is why Expert Determination exists as an alternative route. Chapter 2 covers the distinction.
Date every validator. Identifier schemes change. EIN prefixes get added, MBI patterns get clarified, and card ranges shift. Put a comment naming the scheme and the year you verified it, plus a golden test with known-valid examples, so a scheme revision fails a build rather than silently returning false for every legitimate identifier.
Never loosen for recall. This layer's value is that when it fires it is right. Chase recall in the model layer, where a false positive costs a redacted word rather than a broken validator.
ABANumberCheckDigit reference implementation: https://commons.apache.org/validator/apidocs/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigit.html · algorithm description: http://www.brainjar.com/js/validation/80840 + NPI — CMS, Requirements for National Provider Identifier (NPI) and NPI Check Digit: https://www.cms.gov/Regulations-and-Guidance/Administrative-Simplification/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf · worked example: https://www.johndcook.com/blog/2024/06/26/npi-number/Every validator in this appendix was executed against the stated known-valid test values before publication. The SSN, ITIN, EIN and MBI rules are shape and range checks, not checksums, and the text says so at each one.
Download the full PDF for free?
Free download — no account required