{"id":"GHSA-jfv7-ghgv-gx4x","kind":"vulnerability","aliases":["GHSA-jfv7-ghgv-gx4x"],"related":[],"title":"Quadratic time timedelta validation in Pydantic V1","description":"### Summary\r\n\r\nValidating an untrusted ISO 8601 duration string into a [`timedelta`](https://docs.python.org/3/library/datetime.html#datetime.timedelta) field with Pydantic V1 takes quadratic time: an input of a few dozen kilobytes takes seconds to validate.\r\n\r\n### Details\r\n\r\nThe [`iso8601_duration_re`](https://github.com/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py#L45) regular expression used to parse ISO 8601 durations (in [`pydantic/datetime_parse.py`](https://github.com/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py)) contains an unescaped `.`, which also matches digits:\r\n\r\n```python\r\niso8601_duration_re = re.compile(\r\n    r'^(?P<sign>[-+]?)'\r\n    r'P'\r\n    r'(?:(?P<days>\\d+(.\\d+)?)D)?'\r\n    r'(?:T'\r\n    r'(?:(?P<hours>\\d+(.\\d+)?)H)?'\r\n    r'(?:(?P<minutes>\\d+(.\\d+)?)M)?'\r\n    r'(?:(?P<seconds>\\d+(.\\d+)?)S)?'\r\n    r')?'\r\n    r'$'\r\n)\r\n```\r\n\r\nOn a string of digits, the repeated groups overlap and the regex engine backtracks in quadratic time.\r\n\r\nThe issue was fixed in commit https://github.com/pydantic/pydantic/commit/62791e66a9f8f118e465ed760c9e2ede9ae3055e.\r\n\r\nIf you are relying on the `pydantic.v1` namespace in Pydantic V2, upgrade to [V2.14.2](https://github.com/pydantic/pydantic/releases/tag/v2.14.2) or later.\r\n\r\n### Impact\r\n\r\nDenial of service through validation of untrusted input. Affected are applications validating untrusted strings into [`timedelta`](https://docs.python.org/3/library/datetime.html#datetime.timedelta) fields.","summary":"Pydantic V1 parses ISO 8601 duration strings into timedelta fields with a regular expression that has an unescaped dot, so it matches digits too. A string of a few dozen kilobytes of digits makes validation take seconds, which is a denial of service for any app validating untrusted input.","severity":"medium","cvss":6.9,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"pydantic","note":"<=1.10.27","fixed":["1.10.27"],"affected":"<= 1.10.27","ecosystem":"pypi"}],"ecosystems":["pypi"],"tags":["cwe-1333","package","pydantic","python","web-apis"],"not_affected_if":["no-untrusted-timedelta-input","pydantic-v2-without-v1-namespace"],"how_to_check":"- Check the installed Pydantic version with `pip show pydantic` or `python -c \"import pydantic; print(pydantic.VERSION)\"`; versions at or below `1.10.27` are affected.\n- Look for `timedelta` fields fed from untrusted input, such as request bodies or query parameters.\n- If you use the `pydantic.v1` namespace under Pydantic V2, check that version as well.","fix":"- Pydantic (PyPI) V1: `1.10.27`\n- Pydantic V2 users of the `pydantic.v1` namespace: `2.14.2` or later","status":"open","published_at":"2026-10-29T16:46:27+00:00","first_seen_at":"2026-11-09T22:53:21+00:00","triaged_at":"2026-11-09T22:54:35+00:00","updated_at":"2026-11-09T22:54:35+00:00","category":"package","confidence":0.85,"triage":{"at":"2026-11-09T22:54:35Z","model":"claude-haiku-5-5","output":{"fix":"- Pydantic (PyPI) V1: `1.10.27`\n- Pydantic V2 users of the `pydantic.v1` namespace: `2.14.2` or later","reach":"network","title":"Pydantic V1: quadratic-time regex lets a long duration string stall validation","impact":"low","summary":"Pydantic V1 parses ISO 8601 duration strings into timedelta fields with a regular expression that has an unescaped dot, so it matches digits too. A string of a few dozen kilobytes of digits makes validation take seconds, which is a denial of service for any app validating untrusted input.","audience":"developers","category":"package","nicknames":[],"who_cares":["python","pydantic","web-apis"],"confidence":0.85,"fix_status":"available","needs_auth":"unknown","worst_case":"Validation service stalls on crafted input, causing denial of service","analyst_note":"","how_to_check":"- Check the installed Pydantic version with `pip show pydantic` or `python -c \"import pydantic; print(pydantic.VERSION)\"`; versions at or below `1.10.27` are affected.\n- Look for `timedelta` fields fed from untrusted input, such as request bodies or query parameters.\n- If you use the `pydantic.v1` namespace under Pydantic V2, check that version as well.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["no-untrusted-timedelta-input","pydantic-v2-without-v1-namespace"],"who_is_affected":"Applications that parse untrusted ISO 8601 duration strings into timedelta fields using Pydantic V1, or the pydantic.v1 namespace in Pydantic V2. Services that only handle trusted internal data, or that do not accept timedelta values from users, are not exposed.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"no","severity_if_unknown":"medium"},"cost_usd":0.000853,"input_tokens":5207,"output_tokens":664,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-1333':20B '/3/library/datetime.html#datetime.timedelta)':89C,233C '/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py#l45)':115C '/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py))':128C '/pydantic/pydantic/commit/62791e66a9f8f118e465ed760c9e2ede9ae3055e.':194C '/pydantic/pydantic/releases/tag/v2.14.2)':211C '8601':31B,81C,122C 'affect':223C 'also':133C 'api':26B 'app':72B 'applic':225C 'backtrack':182C 'commit':191C 'contain':129C 'cwe':19B 'd':147C,148C,149C,154C,155C,159C,160C,164C,165C 'denial':67B,215C 'detail':108C 'digit':49B,59B,135C,173C 'docs.python.org':88C,232C 'docs.python.org/3/library/datetime.html#datetime.timedelta)':87C,231C 'dot':45B 'dozen':56B,102C 'durat':32B,82C,111C,123C,138C 'engin':181C 'express':40B,117C 'field':36B,90C,234C 'fix':189C 'ghgv':11A,16A 'ghsa':9A,14A 'ghsa-jfv7-ghgv-gx4x':8A,13A 'github.com':114C,127C,193C,210C 'github.com/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py#l45)':113C 'github.com/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py))':126C 'github.com/pydantic/pydantic/commit/62791e66a9f8f118e465ed760c9e2ede9ae3055e.':192C 'github.com/pydantic/pydantic/releases/tag/v2.14.2)':209C 'group':176C 'gx4x':12A,17A 'h':156C 'impact':214C 'input':75B,98C,222C 'iso':30B,80C,121C 'iso8601':110C,137C 'issu':187C 'jfv7':10A,15A 'kilobyt':57B,103C 'later':213C 'm':161C 'make':60B 'match':48B,134C 'namespac':202C 'overlap':177C 'p':142C,144C,146C,153C,158C,163C 'packag':21B 'pars':29B,120C 'pydant':6A,22B,27B,92C,204C 'pydantic':18A 'pydantic.v1':201C 'pydantic/datetime_parse.py':125C 'python':23B,136C 'quadrat':1A,95C,184C 'r':141C,143C,145C,150C,152C,157C,162C,167C,168C 're':112C,139C 're.compile':140C 'regex':180C 'regular':39B,116C 'reli':198C 'repeat':175C 'second':63B,105C 'servic':69B,217C 'string':33B,52B,83C,171C,228C 'summari':76C 'take':62B,94C,104C 'time':2A,96C,185C 'timedelta':3A,35B,86C,230C 'unescap':44B,131C 'untrust':74B,79C,221C,227C 'upgrad':206C 'use':118C 'v1':7A,28B,93C 'v2':205C 'v2.14.2':208C 'valid':4A,61B,73B,77C,107C,219C,226C 'web':25B 'web-api':24B","nicknames":[],"mitigations":[],"who_affected":"Applications that parse untrusted ISO 8601 duration strings into timedelta fields using Pydantic V1, or the pydantic.v1 namespace in Pydantic V2. Services that only handle trusted internal data, or that do not accept timedelta values from users, are not exposed.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["pydantic"],"ptokens":["pydantic"],"labels":["cwe1333","medium","package","pydantic","pypi","python","webapis"],"campaign_type":null,"search_a":"'ghgv':11A,16A 'ghsa':9A,14A 'ghsa-jfv7-ghgv-gx4x':8A,13A 'gx4x':12A,17A 'jfv7':10A,15A 'pydant':6A 'pydantic':18A 'quadrat':1A 'time':2A 'timedelta':3A 'v1':7A 'valid':4A","search_b":"'-1333':20B '8601':31B 'api':26B 'app':72B 'cwe':19B 'denial':67B 'digit':49B,59B 'dot':45B 'dozen':56B 'durat':32B 'express':40B 'field':36B 'input':75B 'iso':30B 'kilobyt':57B 'make':60B 'match':48B 'packag':21B 'pars':29B 'pydant':22B,27B 'python':23B 'regular':39B 'second':63B 'servic':69B 'string':33B,52B 'take':62B 'timedelta':35B 'unescap':44B 'untrust':74B 'v1':28B 'valid':61B,73B 'web':25B 'web-api':24B","search_c":"'/3/library/datetime.html#datetime.timedelta)':89C,233C '/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py#l45)':115C '/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py))':128C '/pydantic/pydantic/commit/62791e66a9f8f118e465ed760c9e2ede9ae3055e.':194C '/pydantic/pydantic/releases/tag/v2.14.2)':211C '8601':81C,122C 'affect':223C 'also':133C 'applic':225C 'backtrack':182C 'commit':191C 'contain':129C 'd':147C,148C,149C,154C,155C,159C,160C,164C,165C 'denial':215C 'detail':108C 'digit':135C,173C 'docs.python.org':88C,232C 'docs.python.org/3/library/datetime.html#datetime.timedelta)':87C,231C 'dozen':102C 'durat':82C,111C,123C,138C 'engin':181C 'express':117C 'field':90C,234C 'fix':189C 'github.com':114C,127C,193C,210C 'github.com/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py#l45)':113C 'github.com/pydantic/pydantic/blob/v1.10.26/pydantic/datetime_parse.py))':126C 'github.com/pydantic/pydantic/commit/62791e66a9f8f118e465ed760c9e2ede9ae3055e.':192C 'github.com/pydantic/pydantic/releases/tag/v2.14.2)':209C 'group':176C 'h':156C 'impact':214C 'input':98C,222C 'iso':80C,121C 'iso8601':110C,137C 'issu':187C 'kilobyt':103C 'later':213C 'm':161C 'match':134C 'namespac':202C 'overlap':177C 'p':142C,144C,146C,153C,158C,163C 'pars':120C 'pydant':92C,204C 'pydantic.v1':201C 'pydantic/datetime_parse.py':125C 'python':136C 'quadrat':95C,184C 'r':141C,143C,145C,150C,152C,157C,162C,167C,168C 're':112C,139C 're.compile':140C 'regex':180C 'regular':116C 'reli':198C 'repeat':175C 'second':105C 'servic':217C 'string':83C,171C,228C 'summari':76C 'take':94C,104C 'time':96C,185C 'timedelta':86C,230C 'unescap':131C 'untrust':79C,221C,227C 'upgrad':206C 'use':118C 'v1':93C 'v2':205C 'v2.14.2':208C 'valid':77C,107C,219C,226C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-29T16:46:27+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-jfv7-ghgv-gx4x","url":"https://github.com/pydantic/pydantic/security/advisories/GHSA-jfv7-ghgv-gx4x","severity":"medium","published_at":"2026-10-29T16:46:27+00:00","modified_at":"2026-10-29T16:46:28+00:00","first_seen_at":"2026-11-09T22:53:21+00:00","fetched_at":"2026-11-09T22:53:21+00:00","note":null}],"documents":[{"id":110526,"url":"https://github.com/pydantic/pydantic/security/advisories/GHSA-jfv7-ghgv-gx4x","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}