Skip to content

fix(isCreditCard): anchor mastercard regex so partial strings are rejected#2747

Open
LorenzoGalassi wants to merge 1 commit into
validatorjs:masterfrom
LorenzoGalassi:fix/2717-mastercard-regex-anchoring
Open

fix(isCreditCard): anchor mastercard regex so partial strings are rejected#2747
LorenzoGalassi wants to merge 1 commit into
validatorjs:masterfrom
LorenzoGalassi:fix/2717-mastercard-regex-anchoring

Conversation

@LorenzoGalassi

Copy link
Copy Markdown

Closes #2717

Problem

isCreditCard("5108") returns true, and so do many other short or partial strings beginning with 51-55.

The mastercard pattern is:

mastercard: /^5[1-5][0-9]{2}|(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$/

| binds looser than the ^ and $ anchors, so this is really the union of two half-anchored patterns:

  1. ^5[1-5][0-9]{2} — start-anchored only, matches any string starting with 51XX-55XX regardless of length.
  2. (222[1-9]|...|2720)[0-9]{12}$ — end-anchored only.

So format validation degenerated to "starts with 51-55" or "ends with a 2-series BIN + 12 digits". "5108" matches branch 1 and also happens to be Luhn-valid, so isCreditCard returned true.

Fix

Wrap the alternation in a non-capturing group so both anchors and the trailing [0-9]{12} apply to every branch:

mastercard: /^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$/

All Mastercard numbers are 16 digits (4-digit BIN prefix + 12), which the grouped pattern now enforces for both the 5x and 2x ranges.

I audited the other six card patterns in this file for the same |-precedence issue; only mastercard was affected. (unionpay looks unusual but its branches are correctly wrapped in ^(...)$, so it is not impacted.)

Tests

Added 5108 to the invalid lists in both the Mastercard-provider and no-provider isCreditCard test blocks.

  • npm run build + full validators.test.js suite: 249 passing.
  • Verified the new cases are meaningful: reverting only the regex change makes exactly those two assertions fail (isCreditCard("5108") and isCreditCard("5108", { provider: "Mastercard" })) and nothing else.
  • Valid Mastercards (both 51-55 and the 2221-2720 2-series BINs) continue to validate; "5108", "5108foo" now correctly return false.
  • eslint src test passes.

…ected

The mastercard pattern was /^5[1-5][0-9]{2}|(...)[0-9]{12}$/. Because the
alternation was not grouped, | bound looser than the ^ and $ anchors, so
the regex matched either "starts with 51-55" (no length bound) or "ends
with a 2-series BIN + 12 digits". As a result isCreditCard("5108"), which
is also Luhn-valid, incorrectly returned true.

Wrap the alternation in a non-capturing group so both anchors and the
trailing [0-9]{12} apply to every branch, and add 5108 to the Mastercard
and no-provider invalid test lists.

Closes validatorjs#2717
@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (7fdc788) to head (f247e1a).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #2747   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          114       114           
  Lines         2587      2587           
  Branches       656       656           
=========================================
  Hits          2587      2587           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

isCreditCard: Mastercard regex anchoring bug accepts 4-digit and partial strings

1 participant