CVE-2026-114603
OpenTelemetry Python: Unbounded tracestate parsing in opentelemetry-api
OpenTelemetry Python provides the Python API and SDK for OpenTelemetry. Prior to 1.45.1, the opentelemetry-api function TraceState.from_header in opentelemetry/trace/span.py, reached through TraceContextTextMapPropagator.extract, parses inbound W3C tracestate headers with an unbounded optional-whitespace regular expression. A malformed header containing a long run of spaces or tabs without a following comma causes quadratic backtracking before the member-count limit is applied. Services using the default W3C Trace Context propagator can therefore spend excessive CPU time on one unauthenticated request when the HTTP server, parser, gateway, or custom carrier accepts a sufficiently large header. The processing can occupy a synchronous worker or delay unrelated requests on the same asynchronous event loop. The impact is limited to availability and does not expose or modify telemetry data or allow code execution. This issue is fixed in version 1.45.1.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- Low
Exploit likelihood
What each source reports
CVE List Score used
5.3
OpenTelemetry Python: Unbounded tracestate parsing in opentelemetry-api
OpenTelemetry Python provides the Python API and SDK for OpenTelemetry. Prior to 1.45.1, the opentelemetry-api function TraceState.from_header in opentelemetry/trace/span.py, reached through TraceContextTextMapPropagator.extract, parses inbound W3C tracestate headers with an unbounded optional-whitespace regular expression. A malformed header containing a long run of spaces or tabs without a following comma causes quadratic backtracking before the member-count limit is applied. Services using the default W3C Trace Context propagator can therefore spend excessive CPU time on one unauthenticated request when the HTTP server, parser, gateway, or custom carrier accepts a sufficiently large header. The processing can occupy a synchronous worker or delay unrelated requests on the same asynchronous event loop. The impact is limited to availability and does not expose or modify telemetry data or allow code execution. This issue is fixed in version 1.45.1.
- Record
CVE-2026-114603- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - Weakness
- CWE-400, CWE-1333
- Updated
- 2026-11-02
EUVDEUVD-2026-108216
5.3
OpenTelemetry Python provides the Python API and SDK for OpenTelemetry. Prior to 1.45.1, the opentelemetry-api function TraceState.from_header in opentelemetry/trace/span.py, reached through TraceContextTextMapPropagator.extract, parses inbound W3C tracestate headers with an unbounded optional-whitespace regular expression. A malformed header containing a long run of spaces or tabs without a following comma causes quadratic backtracking before the member-count limit is applied. Services using the default W3C Trace Context propagator can therefore spend excessive CPU time on one unauthenticated request when the HTTP server, parser, gateway, or custom carrier accepts a sufficiently large header. The processing can occupy a synchronous worker or delay unrelated requests on the same asynchronous event loop. The impact is limited to availability and does not expose or modify telemetry data or allow code execution. This issue is fixed in version 1.45.1.
- Record
EUVD-2026-108216- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-xcq7-p3pf-p88h
5.3
OpenTelemetry Python: Unbounded tracestate parsing in opentelemetry-api
Summary
TraceState.from_header splits the inbound W3C tracestate header with a regular expression that starts with an unbounded optional-whitespace run, and no length limit is applied first. A run of spaces or tabs that is not followed by a comma costs O(N²) CPU. A single unauthenticated request with a ~100 KB tracestate keeps the handling worker busy for ~6 s (spaces) to ~12 s (tabs); under an asyncio server it blocks every other connection for that time.
Affected component / version
- Package:
opentelemetry-api(pip) —opentelemetry/trace/span.py(TraceState.from_header), reached fromopentelemetry/trace/propagation/tracecontext.py(TraceContextTextMapPropagator.extract). - Confirmed in
main(5e8083e8) and in the v1.44.0 and v1.45.0 tags; the same pattern is present back to v1.0.0 (introduced by #1599, March 2021). Not exhaustively verified against every release in between. - Reachable with the default propagators (
OTEL_PROPAGATORSdefaults totracecontext,baggage) from any server instrumentation that callspropagate.extract(), for exampleopentelemetry-instrumentation-asgi.
Details
- The header reaches the parser without any length check:
# opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py:57
tracestate_headers = getter.get(carrier, self._TRACESTATE_HEADER_NAME) # <-- attacker-controlled request header(s), any size
if tracestate_headers is None:
tracestate = None
else:
tracestate = TraceState.from_header(tracestate_headers) # <-- no length check before parsing (line 61)
- The split pattern and the parser:
# opentelemetry-api/src/opentelemetry/trace/span.py:45
_TRACECONTEXT_MAXIMUM_TRACESTATE_KEYS = 32 # <-- only enforced later, in TraceState.__init__, after the split
_delimiter_pattern = re.compile(r"[ \t]*,[ \t]*") # <-- (line 46) starts with an unbounded [ \t]*
# span.py:382
@classmethod
def from_header(cls, header_list: list[str]) -> TraceState:
pairs = {} # type: dict[str, str]
for header in header_list:
members: list[str] = re.split(_delimiter_pattern, header) # <-- (line 400) VULNERABLE: O(N^2) on "a=b" + " " * N + "x"
for member in members:
if not member:
continue
match = _member_pattern.fullmatch(member)
if not match:
_logger.warning( # <-- also logs the entire malformed member (up to the whole header)
"Member doesn't match the w3c identifiers format %s",
member,
)
return cls()
...
re.split tries the pattern at every offset. At each offset inside a whitespace run, [ \t]* consumes the rest of the run, finds no ,, backtracks and fails, then the engine moves one character forward and repeats. N characters × up to N steps each = O(N²). The 32-member limit never gets a chance to run because split has to finish first.
- The sibling propagator already has the missing guard:
# baggage/propagation/__init__.py:68
_MAX_HEADER_LENGTH = 8192
...
if len(header.encode()) > self._MAX_HEADER_LENGTH: # <-- (line 93) rejected before any regex runs; tracestate has no equivalent
_logger.warning(...)
return context
A 16 KiB header costs ≈ 0.25 s and an 8 KiB header ≈ 0.07 s.
Measured cost of extract() on one core (valid traceparent, tracestate: "a=b" + N spaces + "x"): the time quadruples each time N doubles (see the proof of concept). Roughly 0.06 s at 10,000 characters, 1 s at 40,000, 4 s at 80,000, 9 s at 100,000 (tabs are about 1.6× slower).
Whether a server lets such a header through (header-size limits, tested): gunicorn rejects ≥ 8190 bytes (response code 431); uvicorn --http h11 rejects above 16 KiB (400); waitress accepts up to 256 KiB (200 KB accepted, 300 KB rejected); uvicorn --http httptools — the default parser with…
- Record
GHSA-xcq7-p3pf-p88h- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - Weakness
- CWE-400, CWE-1333
- Updated
- 2026-11-02
NVD
5.3
OpenTelemetry Python provides the Python API and SDK for OpenTelemetry. Prior to 1.45.1, the opentelemetry-api function TraceState.from_header in opentelemetry/trace/span.py, reached through TraceContextTextMapPropagator.extract, parses inbound W3C tracestate headers with an unbounded optional-whitespace regular expression. A malformed header containing a long run of spaces or tabs without a following comma causes quadratic backtracking before the member-count limit is applied. Services using the default W3C Trace Context propagator can therefore spend excessive CPU time on one unauthenticated request when the HTTP server, parser, gateway, or custom carrier accepts a sufficiently large header. The processing can occupy a synchronous worker or delay unrelated requests on the same asynchronous event loop. The impact is limited to availability and does not expose or modify telemetry data or allow code execution. This issue is fixed in version 1.45.1.
- Record
CVE-2026-114603- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - Weakness
- CWE-400, CWE-1333
- Updated
- 2026-11-02
OSV
5.3
OpenTelemetry Python: Unbounded tracestate parsing in opentelemetry-api
OpenTelemetry Python provides the Python API and SDK for OpenTelemetry. Prior to 1.45.1, the opentelemetry-api function TraceState.from_header in opentelemetry/trace/span.py, reached through TraceContextTextMapPropagator.extract, parses inbound W3C tracestate headers with an unbounded optional-whitespace regular expression. A malformed header containing a long run of spaces or tabs without a following comma causes quadratic backtracking before the member-count limit is applied. Services using the default W3C Trace Context propagator can therefore spend excessive CPU time on one unauthenticated request when the HTTP server, parser, gateway, or custom carrier accepts a sufficiently large header. The processing can occupy a synchronous worker or delay unrelated requests on the same asynchronous event loop. The impact is limited to availability and does not expose or modify telemetry data or allow code execution. This issue is fixed in version 1.45.1.
- Record
CVE-2026-114603- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - Weakness
- CWE-1333, CWE-400
- Updated
- 2026-11-04
OSVDEBIAN-CVE-2026-114603
5.3
OpenTelemetry Python provides the Python API and SDK for OpenTelemetry. Prior to 1.45.1, the opentelemetry-api function TraceState.from_header in opentelemetry/trace/span.py, reached through TraceContextTextMapPropagator.extract, parses inbound W3C tracestate headers with an unbounded optional-whitespace regular expression. A malformed header containing a long run of spaces or tabs without a following comma causes quadratic backtracking before the member-count limit is applied. Services using the default W3C Trace Context propagator can therefore spend excessive CPU time on one unauthenticated request when the HTTP server, parser, gateway, or custom carrier accepts a sufficiently large header. The processing can occupy a synchronous worker or delay unrelated requests on the same asynchronous event loop. The impact is limited to availability and does not expose or modify telemetry data or allow code execution. This issue is fixed in version 1.45.1.
- Record
DEBIAN-CVE-2026-114603- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - Updated
- 2026-11-02
OSVGHSA-xcq7-p3pf-p88h
5.3
OpenTelemetry Python: Unbounded tracestate parsing in opentelemetry-api
Summary
TraceState.from_header splits the inbound W3C tracestate header with a regular expression that starts with an unbounded optional-whitespace run, and no length limit is applied first. A run of spaces or tabs that is not followed by a comma costs O(N²) CPU. A single unauthenticated request with a ~100 KB tracestate keeps the handling worker busy for ~6 s (spaces) to ~12 s (tabs); under an asyncio server it blocks every other connection for that time.
Affected component / version
- Package:
opentelemetry-api(pip) —opentelemetry/trace/span.py(TraceState.from_header), reached fromopentelemetry/trace/propagation/tracecontext.py(TraceContextTextMapPropagator.extract). - Confirmed in
main(5e8083e8) and in the v1.44.0 and v1.45.0 tags; the same pattern is present back to v1.0.0 (introduced by #1599, March 2021). Not exhaustively verified against every release in between. - Reachable with the default propagators (
OTEL_PROPAGATORSdefaults totracecontext,baggage) from any server instrumentation that callspropagate.extract(), for exampleopentelemetry-instrumentation-asgi.
Details
- The header reaches the parser without any length check:
# opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py:57
tracestate_headers = getter.get(carrier, self._TRACESTATE_HEADER_NAME) # <-- attacker-controlled request header(s), any size
if tracestate_headers is None:
tracestate = None
else:
tracestate = TraceState.from_header(tracestate_headers) # <-- no length check before parsing (line 61)
- The split pattern and the parser:
# opentelemetry-api/src/opentelemetry/trace/span.py:45
_TRACECONTEXT_MAXIMUM_TRACESTATE_KEYS = 32 # <-- only enforced later, in TraceState.__init__, after the split
_delimiter_pattern = re.compile(r"[ \t]*,[ \t]*") # <-- (line 46) starts with an unbounded [ \t]*
# span.py:382
@classmethod
def from_header(cls, header_list: list[str]) -> TraceState:
pairs = {} # type: dict[str, str]
for header in header_list:
members: list[str] = re.split(_delimiter_pattern, header) # <-- (line 400) VULNERABLE: O(N^2) on "a=b" + " " * N + "x"
for member in members:
if not member:
continue
match = _member_pattern.fullmatch(member)
if not match:
_logger.warning( # <-- also logs the entire malformed member (up to the whole header)
"Member doesn't match the w3c identifiers format %s",
member,
)
return cls()
...
re.split tries the pattern at every offset. At each offset inside a whitespace run, [ \t]* consumes the rest of the run, finds no ,, backtracks and fails, then the engine moves one character forward and repeats. N characters × up to N steps each = O(N²). The 32-member limit never gets a chance to run because split has to finish first.
- The sibling propagator already has the missing guard:
# baggage/propagation/__init__.py:68
_MAX_HEADER_LENGTH = 8192
...
if len(header.encode()) > self._MAX_HEADER_LENGTH: # <-- (line 93) rejected before any regex runs; tracestate has no equivalent
_logger.warning(...)
return context
A 16 KiB header costs ≈ 0.25 s and an 8 KiB header ≈ 0.07 s.
Measured cost of extract() on one core (valid traceparent, tracestate: "a=b" + N spaces + "x"): the time quadruples each time N doubles (see the proof of concept). Roughly 0.06 s at 10,000 characters, 1 s at 40,000, 4 s at 80,000, 9 s at 100,000 (tabs are about 1.6× slower).
Whether a server lets such a header through (header-size limits, tested): gunicorn rejects ≥ 8190 bytes (response code 431); uvicorn --http h11 rejects above 16 KiB (400); waitress accepts up to 256 KiB (200 KB accepted, 300 KB rejected); uvicorn --http httptools — the default parser with…
- Record
GHSA-xcq7-p3pf-p88h- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - Weakness
- CWE-1333, CWE-400
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-114603
5.3
OpenTelemetry Python provides the Python API and SDK for OpenTelemetry. Prior to 1.45.1, the opentelemetry-api function TraceState.from_header in opentelemetry/trace/span.py, reached through TraceContextTextMapPropagator.extract, parses inbound W3C tracestate headers with an unbounded optional-whitespace regular expression. A malformed header containing a long run of spaces or tabs without a following comma causes quadratic backtracking before the member-count limit is applied. Services using the default W3C Trace Context propagator can therefore spend excessive CPU time on one unauthenticated request when the HTTP server, parser, gateway, or custom carrier accepts a sufficiently large header. The processing can occupy a synchronous worker or delay unrelated requests on the same asynchronous event loop. The impact is limited to availability and does not expose or modify telemetry data or allow code execution. This issue is fixed in version 1.45.1.
- Record
UBUNTU-CVE-2026-114603- CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - Updated
- 2026-11-02
OSVopenSUSE-SU-2026:12408-1 No score
python313-opentelemetry-api-1.45.1-1.1 on GA media
These are all security issues fixed in the python313-opentelemetry-api-1.45.1-1.1 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2026:12408-1- Updated
- 2026-11-04
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
opentelemetry-apiPyPI |
through 1.45.0 | 1.45.1 |
python-opentelemetryDebian:14 |
before 1.45.1-1, plus listed versions 1.35.0-21.38.0-11.38.0-21.39.1-11.39.1-2 Show 7 moreShow less1.40.0-11.41.0-11.41.0-21.42.1-11.43.0-11.44.0-11.44.0-2 |
1.45.1-1 |
opentelemetry-apiPyPI |
before 1.45.1, plus listed versions 0.10b00.11b00.12b00.13b00.14b0 Show 45 moreShow less0.15b00.16b00.16b10.17b00.1a00.2a00.3a00.4a00.4a10.5b00.6b00.7b00.7b10.8b00.9b01.0.01.0.0rc11.1.01.10.01.10a01.11.01.11.11.12.01.12.0rc11.12.0rc21.13.01.14.01.15.01.16.01.17.01.18.01.19.01.2.01.20.01.21.01.22.01.23.01.24.01.25.01.26.01.27.01.28.01.28.11.28.21.29.0 |
1.45.1 |
python-opentelemetryUbuntu:26.10 |
All versions, plus listed versions 1.39.1-21.42.1-11.43.0-11.44.0-11.44.0-2 |
None known |
python-opentelemetryUbuntu:26.04:LTS |
All versions, plus listed versions 1.38.0-11.38.0-21.39.1-11.39.1-2 |
None known |
python-opentelemetry-apiopenSUSE:Tumbleweed |
before 1.45.1-1.1 | 1.45.1-1.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, aliases, facts, references | OSV | |
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-114603 is a medium vulnerability (CVSS 5.3) in Open-telemetry Opentelemetry-python, published October 22, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.49%, the 42nd percentile. Fixed in opentelemetry-api 1.45.1.
References
github.com/open-telemetry/opentelemetry-python/security/advisories/GHSA-xcq7-p3pf-p88h
github.com/open-telemetry/opentelemetry-python/pull/5749
github.com/open-telemetry/opentelemetry-python/commit/d5224bf4ffdf2aee1b592ad238dcc32ca957f26b
github.com/open-telemetry/opentelemetry-python/blob/main/CHANGELOG.md
github.com/open-telemetry/opentelemetry-python/releases/tag/v1.45.1
github.com/advisories/GHSA-xcq7-p3pf-p88h
Show 7 moreShow less
github.com/CVEProject/cvelistV5/tree/main/cves/2026/114xxx/CVE-2026-114603.json
nvd.nist.gov/vuln/detail/CVE-2026-114603
security-tracker.debian.org/tracker/CVE-2026-114603
github.com/open-telemetry/opentelemetry-python
ubuntu.com/security/CVE-2026-114603
cve.org/CVERecord?id=CVE-2026-114603
suse.com/security/cve/CVE-2026-114603
Left out here: 35 versions and the rest of 2 source descriptions. The JSON record has them.