CVE-2026-73196: Ipa: freeipa: authenticated dos in `otptoken-add` via unbounded otp key decoding/re-encoding
A flaw was found in FreeIPA. A low-privilege authenticated user can exploit this vulnerability by submitting an oversized One-Time Password (OTP) key value. This oversized key is then decoded and re-encoded without proper size limits, consuming excessive CPU and memory resources. This can lead to a denial of service, degrading the availability of the IPA service.
Other sources
AIONLYREPORT package: ipa-4.13.1-3.el10 ------ Summary: Authenticated DoS in otptoken-add via unbounded OTP key decoding/re-encoding: a low-privilege authenticated user can submit an oversized ipatokenotpkey value that is Base32-decoded, re-encoded, and embedded into an enrollment URI without an effective size bound, causing excessive CPU and memory use in the IPA API worker handling the request. Requirements to exploit: Authenticated access to the IPA RPC interface as a user allowed to create self-managed OTP tokens, plus the ability to submit an oversized request body that is not rejected earlier by deployment-specific HTTP request-size controls. Component affected: ipa-4.13.1-3.el10, ipaserver/plugins/otptoken.py, OTPTokenKey.convertscalar(), otptokenadd.precallback() Version affected: ipa-4.13.1-3.el10 Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L - 5.3 (MEDIUM) AV:N - The issue is reachable over the network through the authenticated IPA RPC interface. AC:L - Exploitation requires only an oversized valid Base32 ipatokenotpkey value. PR:L - A regular authenticated user with self-service token creation rights is sufficient. UI:N - No victim interaction is required. S:U - The impact remains within the vulnerable IPA service. C:N - No confidentiality impact is established by the available evidence. I:N - No integrity impact is established by the available evidence. A:L - The request can consume worker CPU and memory and degrade service availability, but the available evidence does not establish consistent full-service outage across all deployments and some installations may reduce exposure with request-size limits. Impact: Important. Red Hat classifies flaws that allow remote users to cause denial of service as Important. This issue is reachable through a network-exposed authenticated endpoint, and the supplied materials show default self-managed token creation permissions for ordinary authenticated users. The demonstrated impact is availability degradation rather than confidentiality or integrity loss, and some deployments may reduce exposure with front-end request-size limits, but the established behavior still fits Important more closely than Moderate. Embargo: no Reason: The issue requires authenticated access, is limited to availability impact, and can often be reduced operationally with request-size controls or tighter token-management permissions, so embargo handling does not appear necessary. Acknowledgement: Aisle Research Vulnerability Details: Observed facts: ipatokenotpkey is declared without a size bound, OTPTokenKey.convertscalar() decodes attacker-controlled Base32 input before returning to the normal bytes conversion path, and otptokenadd.precallback() then Base32-encodes the decoded bytes again and URL-encodes them into an otpauth:// URI stored in request context. python OTPTokenKey('ipatokenotpkey?', cliname='key', label=('Key'), doc=('Token secret (Base32; default: random)'), defaultfrom=lambda: os.urandom(KEYLENGTH), autofill=True, force server-side conversion normalizer=lambda x: x, flags=('nodisplay', 'noupdate', 'nosearch'), ), ... class OTPTokenKey(Bytes): """A binary password type specified in base32."""
password = True def convertscalar(self, value, index=None): if isinstance(value, (tuple, list)) and len(value) == 2: (p1, p2) = value if p1 != p2: raise PasswordMismatch(name=self.name) value = p1 if isinstance(value, unicode): try: value = base64.b32decode(value, True) except TypeError as e: raise ConversionError(name=self.name, error=str(e)) return super(OTPTokenKey, self).convertscalar(value) ... Build the URI parameters args = {} args['issuer'] = issuer args['secret'] = base64.b32encode(entryattrs['ipatokenotpkey']) args['digits'] = entryattrs['ipatokenotpdigits'] args['algorithm'] = entryattrs['ipatokenotpalgorithm'].upper() if options['type'] == 'totp': args['period'] = entryattrs['ipatokentotptimestep'] elif options['type'] == 'hotp': args['counter'] = entryattrs['ipatokenhotpcounter']
Build the URI label = urllib.parse.quote(entryattrs['ipatokenuniqueid']) parameters = urllib.parse.urlencode(args) uri = u'otpauth://%s/%s:%s?%s' % (options['type'], issuer, label, parameters) setattr(context, 'uri', uri)
The supplied materials also show a default ACI named Users can create self-managed tokens, so low-privilege authenticated users can reach this code path when token self-management is available as packaged. Reasonable inference: oversized valid Base32 input can force substantial CPU and memory work before the request completes, because the server decodes the supplied key, re-encodes it, URL-encodes the resulting parameters, and constructs a large enrollment URI in the same request path. Repeated or parallel requests can therefore degrade service availability. Open uncertainty: the available materials do not establish a universal crash threshold or prove that every supported deployment accepts arbitrarily large HTTP request bodies. Installations with strict front-end request-size limits may reduce or prevent exploitation before the vulnerable code path is reached. Steps to reproduce: 1. Authenticate to the IPA RPC interface as a normal user. 2. Create a JSON-RPC otptokenadd request with type set to totp and ipatokenotpkey set to a very large valid Base32 string, for example roughly 32 MiB of repeated A. 3. POST the request to /ipa/session/json with Content-Type: application/json using the authenticated session. 4. Observe CPU and memory spikes in the IPA API worker while the request is processed, specifically during Base32 decode, Base32 re-encode, parameter URL encoding, and otpauth:// URI construction. 5. Repeat or parallelize the request to amplify the availability impact. Mitigation: Until a fix is available, enforce conservative HTTP request-body limits in front of /ipa/session/json so oversized payloads are rejected before IPA parameter conversion. If operationally acceptable, restrict self-managed token creation to trusted users and monitor or rate-limit repeated large authenticated requests. Proposed Fix: Reject oversized Base32 input before decode and enforce a decoded-size cap on ipatokenotpkey. diff diff --git a/ipaserver/plugins/otptoken.py b/ipaserver/plugins/otptoken.py — a/ipaserver/plugins/otptoken.py +++ b/ipaserver/plugins/otptoken.py @@ KEYLENGTH = 35 +MAXOTPKEYBYTES = 1024 +# Base32 expansion: 5 bytes -> 8 chars +MAXOTPKEYB32CHARS = ((MAXOTPKEYBYTES + 4) // 5) 8 @@ class OTPTokenKey(Bytes): @@ def convertscalar(self, value, index=None): @@ if isinstance(value, unicode): + if len(value) > MAXOTPKEYB32CHARS: + raise ConversionError(name=self.name, error='OTP key is too large') try: value = base64.b32decode(value, True) except TypeError as e: raise ConversionError(name=self.name, error=str(e)) + if len(value) > MAXOTPKEYBYTES: + raise ConversionError(name=self.name, error='OTP key is too large') @@ OTPTokenKey('ipatokenotpkey?', cliname='key', label=('Key'), doc=('Token secret (Base32; default: random)'), + maxlength=MAXOTPKEYBYTES, defaultfrom=lambda: os.urandom(KEYLENGTH), autofill=True, normalizer=lambda x: x, flags=('nodisplay', 'noupdate', 'nosearch'), ), ------ This report was generated using AI technology. Always review AI-generated content prior to use
— Red Hat
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Mitigation until a fix is available: reject oversized Base32 input for ipatokenotpkey before Base32-decoding/re-encoding so that input does not exceed MAX_OTPKEY_B32_CHARS (derived from MAX_OTPKEY_BYTES = 1024).
FreeIPA (ipaserver/plugins/otptoken.py) JSON-RPC otptoken_add / OTPTokenKey Reject oversized Base32 input for ipatokenotpkey before Base32 decode and before URL-encoding otpauth:// URI construction = enforce a decoded-size cap of ipatokenotpkey (MAX_OTPKEY_BYTES = 1024; MAX_OTPKEY_B32_CHARS = ((MAX_OTPKEY_BYTES + 4) // 5) * 8) - Compensating control
Apply conservative front-end HTTP request-size limits specifically on requests to `/ipa/session/json` (the authenticated JSON-RPC endpoint) to prevent oversized otp key payloads from reaching the unbounded OTP key decoding/re-encoding code path.
- Compensating control
Rate-limit repeated or parallel authenticated requests to the IPA RPC interface / JSON-RPC path used for `otptoken_add` to reduce CPU/memory exhaustion and availability degradation.
- Compensating control
Restrict self-managed token creation permissions for ordinary authenticated users to trusted users only (so low-privilege authenticated users cannot reach `otptoken-add` with oversized ipatokenotpkey).
- Operational
Monitor the IPA API worker handling the request for CPU and memory spikes while attempting to exploit oversized `ipatokenotpkey`, and validate that oversized Base32 inputs are rejected before conversion/URI construction.
Event History
Frequently Asked Questions
Who can exploit this issue?
An attacker needs authenticated access to the IPA RPC interface as a user permitted to create self-managed OTP tokens. The issue also requires that deployment-specific HTTP request-size controls allow the oversized request body through.
Are default request-size controls enough to prevent exploitation?
The available data does not establish whether default controls reject the malicious request. Exposure depends on the HTTP request-size limits configured in the deployment and whether they reject an oversized OTP key before it reaches the IPA API worker.
What can be done if an update cannot be applied immediately?
Restrict access to the IPA RPC interface and limit self-managed OTP token creation to only necessary users. Configure HTTP request-size controls to reject oversized request bodies before they are processed by IPA.
How does exploitation affect the service?
A submitted oversized ipatokenotpkey value is Base32-decoded, re-encoded, and embedded into an enrollment URI without an effective size bound. This can consume excessive CPU and memory in the IPA API worker handling the request and degrade IPA service availability.