From 996db5006ccb1c03e0da6cfeb3e4163fd9b1ca98 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 6 Sep 2026 01:23:06 +0200 Subject: [PATCH] fix: reject MAC address octets with a sign or whitespace (#424) MacAddress.validate_mac_address parsed each octet with int(part, 16), which also accepts a leading +/- sign and surrounding whitespace. As a result strings like -a:-b:-c:-d:-e:-f, +a:+b:+c:+d:+e:+f and " a: b: c: d: e: f" were accepted, with the sign/whitespace variants silently normalized into a valid-looking MAC the caller never supplied. Require both characters of each octet to be hex digits before the int() conversion so malformed octets raise the mac_address_format error like other invalid input. --- HISTORY.md | 2 ++ pydantic_extra_types/mac_address.py | 8 +++++++- tests/test_mac_address.py | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index f19ea91..bea1ef8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,8 @@ ## Latest Changes +* fix(mac_address): reject MAC octets with a sign or whitespace (e.g. `-a:...`, `+a:...`, ` a:...`) that `int(..., 16)` accepted. + ## 2.11.2 * fix: accept common timezone abbreviations like EDT in TimeZoneName validator by @r266-tech in https://github.com/pydantic/pydantic-extra-types/pull/376 diff --git a/pydantic_extra_types/mac_address.py b/pydantic_extra_types/mac_address.py index 6838aa3..c3b27bb 100644 --- a/pydantic_extra_types/mac_address.py +++ b/pydantic_extra_types/mac_address.py @@ -4,6 +4,7 @@ formats, such as IEEE 802 MAC-48, EUI-48, EUI-64, or a 20-octet format. from __future__ import annotations +import string from typing import Any from pydantic import GetCoreSchemaHandler @@ -100,7 +101,12 @@ class MacAddress(str): mac_bytes: list[int] = [] for part in parts: for i in range(0, chunk_len, 2): - mac_bytes.append(int(part[i : i + 2], base=16)) + octet = part[i : i + 2] + # int(octet, 16) also accepts a sign or whitespace, + # which are not valid MAC octets. + if not all(char in string.hexdigits for char in octet): + raise ValueError(octet) + mac_bytes.append(int(octet, base=16)) except ValueError as exc: raise PydanticCustomError('mac_address_format', 'Unrecognized format') from exc diff --git a/tests/test_mac_address.py b/tests/test_mac_address.py index 82f78c9..5704ac3 100644 --- a/tests/test_mac_address.py +++ b/tests/test_mac_address.py @@ -56,6 +56,11 @@ class Network(BaseModel): ('00.00.5e.00.53.01.', None, False), # Extra separator at the end ('00:00:5e:00:53:', None, False), # Incomplete MAC address (float(12345678910111213), None, False), + # int(..., 16) accepts a sign or whitespace; a MAC octet must not. + ('-a:-b:-c:-d:-e:-f', None, False), + ('+a:+b:+c:+d:+e:+f', None, False), + (' a: b: c: d: e: f', None, False), + ('-aaa.-bbb.-ccc', None, False), ], ) def test_format_for_mac_address(mac_address: Any, result: str, valid: bool):