Bug: Unbounded MCP resource pagination loops can cause OOM
What version of Codex CLI is running?
Reproduced with codex-cli 0.145.0. The same implementation is still present in main at e4fb5311d7468839def62eabda4b268f4a54cf11.
What platform is your computer?
Darwin 26.5.2 arm64 arm (macOS).
What issue are you seeing?
MCP resource listing pagination loops have no maximum page count or total resource cap. A misbehaving or malicious MCP server could return a new (non-duplicate) cursor on every page, causing the client to loop indefinitely, accumulate unbounded memory, and potentially OOM.
Affected code locations:
codex-mcp/src/connection_manager/resources.rs:40-59codex-mcp/src/connection_manager/resources.rs:97-122codex-mcp/src/binding_clients.rs:92-115codex-mcp/src/binding_clients.rs:133-158
Root cause: The pagination loops only check for duplicate cursors as a termination condition:
loop {
let response = client.list_resources(params, timeout).await?;
resources.extend(response.resources);
match response.next_cursor {
Some(next) if cursor.as_ref() == Some(&next) => {
return Err(anyhow!("resources/list returned duplicate cursor"));
}
Some(next) => cursor = Some(next),
None => return Ok(resources),
}
}
A server that returns a new cursor on every page (e.g., cursor1, cursor2, cursor3, ...) would cause the client to loop indefinitely. Each page adds to the resources vector, so memory grows without bound.
Impact: Denial of service via OOM. A malicious or buggy MCP server could crash the Codex process by returning infinite pagination cursors.
What steps can reproduce the bug?
- Configure an MCP server that returns a new cursor on every
resources/listcall - Start Codex CLI
- The client will loop indefinitely, consuming memory until OOM
What is the expected behavior?
The pagination loop should have a maximum page count (e.g., 100 pages) and break with a warning when exceeded.
Suggested fix
Add a MAX_RESOURCE_PAGES constant and break the loop when exceeded:
const MAX_RESOURCE_PAGES: usize = 100;
loop {
let response = client.list_resources(params, timeout).await?;
resources.extend(response.resources);
if resources.len() > MAX_RESOURCE_PAGES * 1000 {
warn!("resource listing exceeded maximum pages, stopping");
break;
}
match response.next_cursor {
Some(next) if cursor.as_ref() == Some(&next) => {
return Err(anyhow!("resources/list returned duplicate cursor"));
}
Some(next) => cursor = Some(next),
None => return Ok(resources),
}
}
Related
- #28858 — Codex does not follow MCP
tools/listpagination vianextCursor(opposite problem)
Scope
Four call sites in two files. The fix is ~10 lines per call site. No behavioral change for正常 servers — only protection against misbehaving servers.