Bug 2478495 (CVE-2026-92824) - CVE-2026-92824 libmodulemd: libmodulemd: out-of-bounds read when emitting rpm-map artifacts
Summary: CVE-2026-92824 libmodulemd: libmodulemd: out-of-bounds read when emitting rpm...
Keywords:
Status: NEW
Alias: CVE-2026-92824
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Product Security DevOps Team
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-05-18 03:36 UTC by OSIDB Bzimport
Modified: 2026-10-21 03:10 UTC (History)
18 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-05-18 03:36:39 UTC
AI_ONLY_REPORT
package: libmodulemd-2.15.2-7.1.hum1
------
Summary: Incorrect inner loop bound in rpm-map emission causes  
out-of-bounds read: crafted modulemd v2 metadata with multiple digest types  
can trigger an out-of-bounds read and likely crash during YAML  
serialization.
Requirements to exploit: An attacker must supply crafted modulemd v2 input  
to a libmodulemd consumer that parses `data.artifacts.rpm-map` and later  
serializes the resulting object. No privileges are needed beyond control of  
that input. Remote reachability depends on the consuming application; the  
library itself does not expose a network service.
Component affected: `libmodulemd-2.15.2-7.1.hum1`,  
`modulemd/modulemd-module-stream-v2.c`,  
`modulemd_module_stream_v2_emit_rpm_map()`
Version affected: `libmodulemd-2.15.2-7.1.hum1`
Patch available: no released package fix established; proposed patch  
included below
Version fixed: unknown
Upstream coordination: This report serves as the initial notification.
CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - 6.2 (MEDIUM)
AV:L - The vulnerable behavior is in a library code path reached when a  
local caller supplies crafted module metadata; the library does not itself  
provide a network-facing service.
AC:L - The trigger condition is simple: at least two digest algorithms  
in `rpm-map`, with fewer checksum entries in one per-digest map than the  
total digest count.
PR:N - No privileges are required beyond the ability to provide the  
malformed modulemd document to an affected consumer.
UI:N - Once the document is parsed and later serialized, the fault  
occurs automatically.
S:U - The impact is limited to the consuming process.
C:N - No confidentiality impact is established.
I:N - No integrity impact is established.
A:H - The out-of-bounds read occurs in the emit path and is likely to  
abort or crash the process.
Impact: Moderate. Under Red Hat guidance, Important is generally reserved  
for issues that easily compromise confidentiality, integrity, or  
availability, including easy remote denial of service. Here the established  
impact is denial of service in a library consumer, but exploitation depends  
on a specific parse-then-emit workflow rather than a default exposed  
service. That makes Moderate a better fit than Important, while Low would  
understate a real memory-safety flaw with a concrete crash path.
Embargo: no
Reason: This is an availability-focused library flaw with a  
straightforward one-line fix and usage-dependent reachability. The current  
evidence does not support an easily exploitable default remote compromise  
scenario.
Acknowledgement: Aisle Research
Vulnerability Details: In `modulemd_module_stream_v2_emit_rpm_map()`, the  
outer loop iterates over the top-level digest algorithms in  
`self->rpm_artifact_map`. Inside that loop, the code creates a `checksums`  
array for the current `digest_table`, but the inner loop incorrectly uses  
`digests->len` as its bound instead of `checksums->len`:
```c
digests =
modulemd_ordered_str_keys (self->rpm_artifact_map,  
modulemd_strcmp_sort);
...
checksums =
modulemd_ordered_str_keys (digest_table, modulemd_strcmp_sort);
for (guint j = 0; j < digests->len; j++)
{
checksum = g_ptr_array_index (checksums, j);
EMIT_SCALAR (emitter, error, checksum);
entry = g_hash_table_lookup (digest_table, checksum);
if (!modulemd_rpm_map_entry_emit_yaml (entry, emitter, error))
{
return FALSE;
}
}
```
`digests` is global across digest types, while `checksums` belongs only to  
the current digest table. If a document contains two or more digest  
algorithms but a given digest map has fewer checksum keys than the total  
number of digest algorithms, `g_ptr_array_index (checksums, j)` reads past  
the end of `checksums`.
The parse path accepts checksum keys directly from YAML and stores them  
under the selected digest:
```c
case YAML_SCALAR_EVENT:
/* Each key in this map is a checksum with the value being a
ModulemdRpmMapEntry
            */
           checksum = (const gchar *)event.data.scalar.value;


entry =
modulemd_rpm_map_entry_parse_yaml (parser, strict,  
&nested_error);
if (!entry)
{
g_propagate_error (error, g_steal_pointer (&nested_error));
return FALSE;
}
modulemd_module_stream_v2_set_rpm_artifact_map_entry (
modulestream, entry, digest, checksum);
```
No matching cardinality check is visible before the object is later  
emitted. The established consequence is an out-of-bounds read in a core  
serialization path, with likely denial-of-service impact. Confidentiality,  
integrity, and code-execution impact were not established. The flaw is  
present in `libmodulemd-2.15.2-7.1.hum1`; a broader affected range is not  
asserted here without authoritative history.
Steps to reproduce:
1. Create a modulemd v2 document with at least two keys under  
`data.artifacts.rpm-map`, while leaving only one checksum entry under each  
digest key.
2. Parse the document with `modulemd_module_stream_read_string()`.
3. Add the resulting stream to an index and serialize it with  
`modulemd_module_index_dump_to_string()` or another path that reaches  
`modulemd_module_stream_v2_emit_rpm_map()`.
4. The serializer will iterate `j < digests->len` while indexing the  
smaller `checksums` array. The expected result is an out-of-bounds read,  
typically causing a crash or abort.
Minimal trigger YAML:
```yaml
—
document: modulemd
version: 2
data:
name: demo
stream: stable
version: 1
context: c0ffee43
summary: s
description: d
license:
module: [MIT]
artifacts:
rpms:
pkg-0:1-1.x86_64
     rpm-map:
       sha256:
         aaa:
           name: pkg
           epoch: 0
           version: "1"
           release: "1"
           arch: x86_64
           nevra: pkg-0:1-1.x86_64
       sha1:
         bbb:
           name: pkg
           epoch: 0
           version: "1"
           release: "1"
           arch: x86_64
           nevra: pkg-0:1-1.x86_64
...
```


Mitigation: Until a fixed package is available, avoid round-tripping  
untrusted modulemd v2 documents that include `artifacts.rpm-map`. If  
untrusted metadata must be accepted, reject or strip `rpm-map` content with  
multiple digest algorithms before serializing the parsed object.
Proposed Fix: The inner loop should be bounded by the per-digest  
`checksums` array rather than the global `digests` array. Adding a  
regression test for multiple digest algorithms with fewer checksum keys in  
at least one digest map would help prevent recurrence.
```diff
diff --git a/modulemd/modulemd-module-stream-v2.c  
b/modulemd/modulemd-module-stream-v2.c
— a/modulemd/modulemd-module-stream-v2.c
+++ b/modulemd/modulemd-module-stream-v2.c
@@ -3267,7 +3267,7 @@ modulemd_module_stream_v2_emit_rpm_map  
(ModulemdModuleStreamV2 *self,
checksums =
modulemd_ordered_str_keys (digest_table, modulemd_strcmp_sort);
     for (guint j = 0; j < digests->len; j++)
+      for (guint j = 0; j < checksums->len; j++)
          {
            checksum = g_ptr_array_index (checksums, j);
            EMIT_SCALAR (emitter, error, checksum);
```


------
This report was generated using AI technology. Always review AI-generated  
content prior to use


Note You need to log in before you can comment on or make changes to this bug.