CVE-2026-92823: Libmodulemd: libmodulemd: missing decompressed-size limit when parsing compressed yaml
A flaw was found in libmodulemd. In builds with rpmio support enabled, compressed modulemd YAML is decompressed through a custom read handler that does not enforce a cumulative decompressed-size limit before parsing. An attacker who can supply a highly compressible compressed YAML file can cause excessive CPU and memory consumption, resulting in a denial of service.
Other sources
AIONLYREPORT package: libmodulemd-2.15.2-7.1.hum1 ------ Summary: Compressed-input path lacks decompressed-size limits (potential decompression bomb DoS): In rpmio-enabled builds, parsing attacker-controlled compressed YAML can trigger excessive CPU and memory consumption because decompressed bytes are not globally limited before parsing and subdocument re-emission. Requirements to exploit: A vulnerable consumer must be built with rpmio support enabled or autodetected with librpm present, and it must parse attacker-controlled compressed YAML input. The attacker then supplies a highly compressible payload whose decompressed body is large enough to exhaust CPU and/or memory. Component affected: libmodulemd-2.15.2-7.1.hum1; compressed YAML parsing path in modulemdmoduleindexupdatefromfileext(), compressedstreamreadfn(), YAML re-emission, and ModulemdSubdocumentInfo content duplication. Version affected: libmodulemd-2.15.2-7.1.hum1 (rpmio-enabled builds that parse attacker-controlled compressed YAML input) Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Initial notification with this report. CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - 5.5 (MEDIUM) AV:L - The attacker must get a crafted file processed by a local libmodulemd consumer; the library itself is not a network-facing service. AC:L - Exploitation requires only a highly compressible YAML payload with a large decompressed body and no special race or heap shaping. PR:N - No prior privileges are required to create or provide the malicious input. UI:N - Once a vulnerable consumer accepts the supplied file for parsing, no further user action is required to trigger the exhaustion condition. S:U - The impact is confined to the consuming process and its own resources. C:N - The available evidence does not show unauthorized disclosure of data. I:N - The available evidence does not show unauthorized modification of data or control flow. A:H - The process can consume large amounts of CPU and memory and may terminate or be killed by the system. Impact: Moderate. Under Red Hat's severity guidance, this is best classified as Moderate rather than Important because the issue is availability-only and exploitation depends on a specific build configuration and on a consumer accepting attacker-controlled compressed metadata. It can still cause meaningful service disruption where that path is reachable, so Low would understate the risk. Embargo: no Reason: This is a constrained, availability-only resource-exhaustion issue with straightforward operational mitigations, and the available evidence does not indicate confidentiality loss, integrity loss, privilege gain, or code execution. Acknowledgement: Aisle Research Vulnerability Details: In rpmio-enabled builds, compressed files are routed through rpmio and a custom read handler. The handler forwards decompressed bytes from Fread() without a cumulative decompressed-size limit, and downstream parsing re-emits full YAML subdocuments into growing heap buffers and duplicates them into ModulemdSubdocumentInfo. This creates a compression-amplified resource-exhaustion path: a comparatively small compressed file can expand into large allocations and heavy CPU use before parsing or validation fails. The available evidence supports a denial-of-service condition only; it does not show memory corruption, code execution, or direct confidentiality/integrity impact. c / modulemd/modulemd-module-index.c / return modulemdmoduleindexupdatefromcustom ( self, compressedstreamreadfn, rpmiofd, strict, failures, error); / modulemd/modulemd-compression.c / gint compressedstreamreadfn (void data, unsigned char buffer, sizet size, sizet sizeread) { FDt rpmiofd = (FDt)data; ssizet read = Fread (buffer, sizeof (buffer), size, rpmiofd); ... sizeread = read; return 1; } / modulemd/modulemd-yaml-util.c / yamlstring->str = greallocn (yamlstring->str, total, sizeof (char)); / modulemd/modulemd-subdocument-info.c / self->contents = gstrdup (contents); Large uncompressed YAML can also be expensive to process, but the compressed-input path lowers the delivery cost of oversized logical input because the expanded size is not bounded before these downstream allocations occur. Steps to reproduce: 1. Build or use libmodulemd with rpmio support enabled. 2. Create a highly compressible YAML payload with a very large decompressed body, then compress it with a format accepted by the rpmio-enabled build, such as .xz or .gz. 3. Parse the file with modulemd-validator <payload>.xz or through the API path modulemdmoduleindexupdatefromfile(). 4. Monitor CPU and resident memory with /usr/bin/time -v or an equivalent tool and observe sustained resource growth, potentially ending in OOM or process termination. Mitigation: Until a fix is shipped, avoid parsing attacker-controlled compressed module metadata in rpmio-enabled builds. Where compressed input is required, decompress outside the process under strict size quotas or reject files whose decompressed size exceeds a conservative limit before passing data to libmodulemd. If compressed parsing is not needed, building without rpmio support removes the affected path. Proposed Fix: Track cumulative decompressed bytes in the rpmio read context and abort once a maximum is exceeded, ideally with a configurable limit. This bounds the compressed-input path before further YAML emission and duplication can drive large allocations. diff diff --git a/modulemd/include/private/modulemd-compression-private.h b/modulemd/include/private/modulemd-compression-private.h @@ +typedef struct ModulemdCompressedReadCtx +{ +#ifdef HAVERPMIO + FDt fd; +#endif + sizet maxdecompressedbytes; + sizet totaldecompressedbytes; +} ModulemdCompressedReadCtx; diff --git a/modulemd/modulemd-compression.c b/modulemd/modulemd-compression.c @@ gint compressedstreamreadfn (void data, unsigned char buffer, sizet size, sizet sizeread) { FDt rpmiofd = (FDt)data;
ssizet read = Fread (buffer, sizeof (buffer), size, rpmiofd); + ModulemdCompressedReadCtx ctx = (ModulemdCompressedReadCtx )data; + ssizet read = Fread (buffer, sizeof (buffer), size, ctx->fd); + sizeread = 0; @@
gwarning ("Got error [%d] reading the file", Ferror (rpmiofd)); + gwarning ("Got error [%d] reading the file", Ferror (ctx->fd)); return 0; } + if (ctx->totaldecompressedbytes > ctx->maxdecompressedbytes || + (sizet)read > (ctx->maxdecompressedbytes - ctx->totaldecompressedbytes)) + { + gwarning ("Decompressed input exceeded limit (%zu bytes)", + ctx->maxdecompressedbytes); + return 0; + } + ctx->totaldecompressedbytes += (sizet)read;
sizeread = read; + sizeread = (sizet)read; return 1; } diff --git a/modulemd/modulemd-module-index.c b/modulemd/modulemd-module-index.c @@
return modulemdmoduleindexupdatefromcustom (
self, compressedstreamreadfn, rpmiofd, strict, failures, error); + ModulemdCompressedReadCtx readctx = { + .fd = rpmiofd, + .maxdecompressedbytes = 64 1024 1024, / ideally configurable / + .totaldecompressedbytes = 0, + }; + return modulemdmoduleindexupdatefromcustom ( + self, compressedstreamreadfn, &readctx, strict, failures, error);
------ 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
Build libmodulemd without rpmio support when compressed YAML parsing is not needed, removing the affected compressed-input path.
libmodulemd rpmio support = disabled - Compensating control
For compressed YAML that must be accepted, decompress it outside the libmodulemd-consuming process under strict decompressed-size quotas and reject files exceeding the quota before passing the data to libmodulemd.
Event History
Frequently Asked Questions
Which deployments are exposed to this denial-of-service issue?
A deployment is exposed only if its libmodulemd consumer has rpmio support enabled, or rpmio was autodetected because librpm is present, and it parses compressed YAML supplied by an attacker.
What does an attacker need to exploit the issue?
The attacker needs a way to provide compressed YAML to the vulnerable parsing path. They can then use a highly compressible payload that expands sufficiently during decompression to consume excessive CPU or memory.
Is uncompressed YAML affected?
The reported issue is in the compressed-input parsing path. The provided information identifies compressed YAML decompression as the condition that lacks a cumulative decompressed-size limit.