Bug 2479002 (CVE-2026-92822) - CVE-2026-92822 libmodulemd: libmodulemd: unbounded recursion when parsing nested xmd YAML
Summary: CVE-2026-92822 libmodulemd: libmodulemd: unbounded recursion when parsing nes...
Keywords:
Status: NEW
Alias: CVE-2026-92822
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:52 UTC by OSIDB Bzimport
Modified: 2026-10-21 03:09 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:52:16 UTC
AI_ONLY_REPORT
package: libmodulemd-2.15.2-7.1.hum1
------
Summary: Unbounded recursion while parsing attacker-controlled XMD YAML  
into nested GVariant: denial of service is possible when deeply nested  
`xmd` YAML is recursively converted into `GVariant` values without  
recursion-depth or node-count limits, leading to stack exhaustion and  
excessive parser resource consumption.
Requirements to exploit: The attacker must be able to cause an application  
or tool using `libmodulemd-2.15.2-7.1.hum1` to parse attacker-controlled  
modulemd YAML containing a deeply nested `xmd` field. This is reachable  
through public parsing interfaces such as  
`modulemd_module_index_update_from_string()`,  
`modulemd_module_index_update_from_stream()`,  
`modulemd_module_index_update_from_custom()`, or tooling such as  
`modulemd-validator`. No privileges are required, but environments that  
only ingest trusted metadata materially reduce exposure.
Component affected: `libmodulemd-2.15.2-7.1.hum1`, primarily  
`modulemd/modulemd-yaml-util.c` (`mmd_parse_xmd()`,  
`mmd_variant_from_mapping()`, `mmd_variant_from_sequence()`), reached from  
the `xmd` handling in `modulemd/modulemd-module-stream-v1.c`,  
`modulemd/modulemd-module-stream-v2.c`, and  
`modulemd/modulemd-packager-v3.c`.
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: Not notified.
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 evidence shows a library/parser issue triggered when a local  
consumer parses attacker-controlled modulemd YAML; the available materials  
do not establish a network-facing service in this package.
AC:L - A sufficiently deep `xmd` nesting structure is enough to drive  
the vulnerable recursion.
PR:N - No privileges are required to supply malicious metadata to a  
parser that accepts attacker-controlled input.
UI:N - No separate human action is required beyond the normal parsing of  
the supplied document.
S:U - The failure remains within the security scope of the parsing  
process.
C:N - The available evidence does not show confidentiality impact.
I:N - The available evidence does not show integrity impact.
A:H - The parser can crash, abort, or consume substantial resources,  
causing a denial of service.
Impact: Moderate. Based on the Red Hat severity guidance, the supported  
impact is availability loss rather than code execution or data exposure.  
The issue can be serious for consumers that parse untrusted module  
metadata, but exploitability depends on attacker control over the parsed  
YAML and is therefore deployment-dependent rather than an easily  
exploitable remote service case.
Embargo: no
Reason: The available evidence supports a moderate, availability-only  
parser denial of service. Exploitation depends on a consumer accepting  
attacker-controlled modulemd content, and straightforward operational  
mitigations exist until a code fix is shipped.
Acknowledgement: Aisle Research
Vulnerability Details: `libmodulemd-2.15.2-7.1.hum1` parses `xmd` content  
in module stream v1, module stream v2, and packager v3 documents by calling  
`mmd_parse_xmd()` when the `xmd` key is encountered. `mmd_parse_xmd()`  
dispatches YAML mappings to `mmd_variant_from_mapping()`, and the  
conversion helpers recurse again whenever nested mappings or sequences are  
seen. The available code does not show a recursion-depth limit or a  
total-node limit in this path.
The following excerpt from `modulemd/modulemd-yaml-util.c` shows the  
recursive descent in `mmd_variant_from_mapping()`:
```c
...
case YAML_MAPPING_START_EVENT:
value = mmd_variant_from_mapping (parser, &nested_error);
if (!value)
{
g_propagate_error (error, g_steal_pointer  
(&nested_error));
return NULL;
}
break;
case YAML_SEQUENCE_START_EVENT:
value = mmd_variant_from_sequence (parser, &nested_error);
if (!value)
{
g_propagate_error (error, g_steal_pointer  
(&nested_error));
return NULL;
}
break;
...
```
`mmd_variant_from_sequence()` contains the same recursive pattern for  
nested mappings and nested sequences. Because this descent is unbounded,  
sufficiently deep attacker-controlled `xmd` YAML can exhaust stack space  
and may also create severe parse-time CPU or memory pressure. The clearest  
supported outcome is denial of service. The available evidence does not  
establish confidentiality, integrity, or code execution impact.
Steps to reproduce:
1. Build libmodulemd and `modulemd-validator` with sanitizers if available,  
and set a typical stack limit such as `ulimit -s 8192`.
2. Create a modulemd v2 document with deeply nested `xmd` content, for  
example:
```yaml
document: modulemd
version: 2
data:
name: demo
stream: s
version: 1
context: c0
arch: x86_64
summary: s
description: d
license: { module: [MIT] }
xmd:  
{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{a:{}}}}}}}}}}}}}}}}}}}}
```
3. Parse the file with `modulemd-validator <file.yaml>`, or feed the same  
content to `modulemd_module_index_update_from_string()`.
4. Increase the nesting depth until parsing fails. The expected result is a  
crash, abort, stack overflow, or severe parse-time resource pressure,  
depending on the runtime environment and stack limit.
5. A backtrace should show the failure through `mmd_parse_xmd()` into the  
`mmd_variant_from_mapping()` / `mmd_variant_from_sequence()` recursion  
chain.
Mitigation: Until a fix is available, avoid parsing untrusted modulemd  
documents containing attacker-controlled `xmd` data. If such input must be  
accepted, reject unusually deep or large `xmd` structures before handing  
them to libmodulemd and isolate parsing in a process with strict stack,  
CPU, and memory limits. If supported by the YAML stack, parser-side depth  
or alias limits should also be enabled.
Proposed Fix: Enforce both a maximum recursion depth and a maximum  
parsed-node count in the `xmd` conversion path, and return an error when  
either limit is exceeded.
```diff
diff --git a/modulemd/modulemd-yaml-util.c b/modulemd/modulemd-yaml-util.c
@@
+#define MMD_XMD_MAX_DEPTH 128
+#define MMD_XMD_MAX_NODES 100000
+
+static GVariant *mmd_variant_from_mapping_limited (
+  yaml_parser_t *parser, GError **error, guint depth, guint *nodes);
+static GVariant *mmd_variant_from_sequence_limited (
+  yaml_parser_t *parser, GError **error, guint depth, guint *nodes);
@@
-GVariant *mmd_variant_from_mapping (yaml_parser_t *parser, GError **error)
+static GVariant *mmd_variant_from_mapping_limited (
+  yaml_parser_t *parser, GError **error, guint depth, guint *nodes)
{
+  if (depth > MMD_XMD_MAX_DEPTH || ++(*nodes) > MMD_XMD_MAX_NODES)
+    MMD_YAML_ERROR_EVENT_EXIT (error, event, "xmd exceeds safety limits");
@@
             value = mmd_variant_from_mapping (parser, &nested_error);
+              value = mmd_variant_from_mapping_limited (
+                parser, &nested_error, depth + 1, nodes);
@@

             value = mmd_variant_from_sequence (parser, &nested_error);
+              value = mmd_variant_from_sequence_limited (
+                parser, &nested_error, depth + 1, nodes);
@@
-GVariant *mmd_variant_from_sequence (yaml_parser_t *parser, GError **error)
+static GVariant *mmd_variant_from_sequence_limited (
+  yaml_parser_t *parser, GError **error, guint depth, guint *nodes)
  {
+  if (depth > MMD_XMD_MAX_DEPTH || ++(*nodes) > MMD_XMD_MAX_NODES)
+    MMD_YAML_ERROR_EVENT_EXIT (error, event, "xmd exceeds safety limits");
@@

         value = mmd_variant_from_mapping (parser, &nested_error);
+          value = mmd_variant_from_mapping_limited (
+            parser, &nested_error, depth + 1, nodes);
@@

         value = mmd_variant_from_sequence (parser, &nested_error);
+          value = mmd_variant_from_sequence_limited (
+            parser, &nested_error, depth + 1, nodes);
@@
  GVariant *mmd_parse_xmd (yaml_parser_t *parser, GError **error)
  {
+  guint nodes = 0;
@@

     variant = mmd_variant_from_mapping (parser, &nested_error);
+      variant = mmd_variant_from_mapping_limited (
+        parser, &nested_error, 1, &nodes);
```


------
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.