VYPR
Medium severity6.2GHSA Advisory· Published May 19, 2026· Updated May 19, 2026

OpenMcdf: Uncatchable infinite loop in DirectoryTree.TryGetDirectoryEntry on crafted CFB directory cycle

CVE-2026-45785

Description

Summary

The BST name-lookup loop in DirectoryTree.TryGetDirectoryEntry (OpenMcdf/DirectoryTree.cs:35-46) walks directory entries by repeatedly calling directories.TryGetSibling(child, siblingType, validateColor). A crafted CFB file with cyclic Left/Right sibling links among directory entries - constructed so the per-step BST-order check in TryGetSibling (DirectoryEntries.cs:84-85) is satisfied at every step - drives this while (child is not null) loop forever. There is no cycle detection in TryGetDirectoryEntry.

Details

The recent Brent's-algorithm commit (`24f445a`) protects DirectoryTreeEnumerator and works correctly for both attached repros - pure EnumerateEntries() throws FileFormatException: Directory tree contains a loop cleanly. The unprotected code path is the lookup-by-name loop, which is reached from multiple public APIs: - RootStorage.OpenStorage(name) / TryOpenStorage(name) - RootStorage.OpenStream(name) / TryOpenStream(name)

The second one matters most: typical consumers iterate EnumerateEntries() and call OpenStream(entry.Name) per Stream entry. With Brent's algorithm catching the enumeration cycle but not the per-entry lookup, callers can still hang as soon as they touch a streamed entry.

PoC

Two minimal repros attached, demonstrating the same lookup-loop bug reached via two different public APIs:

  • repro_lookup.cfb (5,632 bytes) - hangs on direct OpenStorage(name) for a name not present in the directory
  • repro_enumerate.cfb (7,936 bytes) - hangs on OpenStream(entry.Name) called for an entry returned by EnumerateEntries() (the common consumer pattern)

Repro 1 -

OpenStorage(name)

using OpenMcdf;

using var fs = File.OpenRead("repro_lookup.cfb");
using var root = RootStorage.Open(fs);
root.TryOpenStorage("__substg1.0_3001001F", out _);
// process spins at 100% CPU; Ctrl+C required.

Repro 2 -

OpenStream from inside an enumeration loop

using OpenMcdf;

using var fs = File.OpenRead("repro_enumerate.cfb");
using var root = RootStorage.Open(fs);
foreach (var entry in root.EnumerateEntries())   // safe: Brent's catches enumeration cycles
{
    if (entry.Type == EntryType.Stream)
        _ = root.OpenStream(entry.Name);          // hangs: lookup path has no cycle detection
}

Both processes will not terminate.

(Note: pure foreach (var entry in root.EnumerateEntries()) { } with no per-entry lookup is safe - Brent's algorithm in DirectoryTreeEnumerator catches the enumeration cycle and throws FileFormatException: Directory tree contains a loop. The hang only manifests once a name lookup is performed.)

repros.zip

Impact

A denial of service affecting any application that opens untrusted CFB files with OpenMcdf. A small crafted input with a cyclic directory tree reaches the unprotected BST name-lookup in DirectoryTree.TryGetDirectoryEntry, hit by any caller of OpenStorage / TryOpenStorage / OpenStream / TryOpenStream - including the very common pattern of iterating EnumerateEntries() and calling OpenStream(entry.Name) per Stream entry. The cycles bypass the per-step BST-order check in TryGetSibling, so no exception is thrown and try/catch cannot protect callers. The affected thread is unrecoverable without killing the process. Downstream CFB consumers (e.g. .msg-file parsers) inherit transitively.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Crafted CFB file with cyclic sibling links causes infinite loop in OpenMcdf's directory tree lookup, leading to denial of service.

Vulnerability

The vulnerability resides in DirectoryTree.TryGetDirectoryEntry (OpenMcdf/DirectoryTree.cs:35-46), which iterates through directory entries by repeatedly calling directories.TryGetSibling(child, siblingType, validateColor). A crafted Compound File Binary (CFB) file with cyclic Left/Right sibling links among directory entries, constructed so that the per-step BST-order check in TryGetSibling (DirectoryEntries.cs:84-85) is satisfied at every step, causes the while (child is not null) loop to run indefinitely. There is no cycle detection in TryGetDirectoryEntry. This code path is reachable from public APIs such as RootStorage.OpenStorage(name), TryOpenStorage(name), OpenStream(name), and TryOpenStream(name). All versions of OpenMcdf prior to a fix implementing cycle detection in TryGetDirectoryEntry are affected [1][2].

Exploitation

An attacker can exploit this by providing a specially crafted CFB file that contains cyclic sibling links. The file must be opened via one of the vulnerable API calls. No authentication or special privileges are required; the user only needs to open the malicious file using a vulnerable version of OpenMcdf. For example, calling root.TryOpenStorage("__substg1.0_3001001F", out _) on a crafted file will trigger the infinite loop, consuming 100% CPU and causing the application to hang [1]. A more common scenario is when a consumer iterates EnumerateEntries() and then calls OpenStream(entry.Name) on each entry; although the enumeration itself is protected by Brent's algorithm and throws an exception on cycles, the subsequent OpenStream call is not protected, leading to a hang [1].

Impact

Successful exploitation results in a denial of service (DoS) condition. The application hangs indefinitely due to an infinite loop, consuming 100% CPU and becoming unresponsive. There is no information disclosure, privilege escalation, or remote code execution; the impact is limited to availability [1][2].

Mitigation

As of the publication of this advisory, no official patch has been released for the lookup vulnerability. The recent commit 24f445a only protects the enumeration path (DirectoryTreeEnumerator), not the lookup path in TryGetDirectoryEntry. Users are advised to avoid opening untrusted CFB files with OpenMcdf until a fix is available. A workaround is to implement a timeout or external watchdog when calling the vulnerable APIs. The maintainers have acknowledged the issue and are expected to release a fix that adds cycle detection to TryGetDirectoryEntry [1][2].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

0

No patches discovered yet.

Vulnerability mechanics

AI mechanics synthesis has not run for this CVE yet.

References

2

News mentions

0

No linked articles in our index yet.