Cap’n Proto is a widely-used data interchange format and Remote Procedure Call (RPC) system. It’s popular thanks to its high performance, compact serialization, and RPC capabilities in C++, Rust, and other languages. In December 2022, security researchers uncovered a serious vulnerability — now known as CVE-2022-46149 — affecting several versions across both C++ and Rust implementations.

If you’re a developer or security-minded engineer using Cap’n Proto, you need to understand this issue. In this post, we’ll break down CVE-2022-46149, show the technical details, provide exploit insights, and explain what you need to do to stay protected.

The Heart of the Issue: Out-of-Bounds Read in List-of-List (Pointer) Handling

The bug lurks in Cap’n Proto’s handling of pointer lists. More specifically, it’s due to a logic error when working with *list-of-list* types — that is, lists where each element is itself a pointer (not just raw data). Under certain situations, a crafted message can trick Cap’n Proto into reading past the end of a memory buffer (out-of-bounds), leading to a crash (segmentation fault) or, in special cases, memory disclosure.

Rust capnp crate: Before .13.7, .14.11, and .15.2

*If your project depends on Cap’n Proto through static or inline code, you must rebuild your application even if you update the Cap’n Proto library!*

Learn more in the official GitHub advisories:  
- C++ Security Advisory  
- Rust Security Advisory

How an Attacker Can Exploit This (And Why It’s Serious)

The vulnerability allows a remote attacker (for example, anyone who can send Cap’n Proto messages to your application) to:

- Crash the program (segfault): By sending a crafted message that, when parsed and processed, tricks Cap’n Proto into reading outside the boundaries of a buffer.
- Memory disclosure (data leak): Under more complex circumstances, if the app performs extra actions on pointer lists, secret data from process memory could be exfiltrated.

This is bad news for servers exposing Cap’n Proto interfaces over the network — a crash is annoying, but a memory leak could lead to things like credential theft.

Exploitation Example

Imagine the bug as a subtle flaw in how Cap’n Proto checks the size of internal arrays. If a message claims to contain N lists, but the wire data only includes N-1, Cap’n Proto’s logic can still allow reading that non-existent Nth pointer. If an attacker controls the message, they can place pointers so that Cap’n Proto "follows" them out of bounds into sensitive memory.

C++ Example: Unsafe Parsing

Here’s a simple C++ snippet that’s *potentially* vulnerable (assuming a list-of-list type is involved):

capnp::SegmentArrayMessageReader messageReader(
    capnp::wordArrayPtrFromBytes(data, size));

// Vulnerable case: parsing a pointer list
auto myList = messageReader.getRoot<MyPointerListType>();

// Actions on myList could trigger the OOB read
auto sublist = myList[attackerControlledIndex];  // <-- Out-of-bounds here!

If attackerControlledIndex is out of range, and bounds checking is faulty, this leads to a segmentation fault — or worse, reading memory you don’t own!

In Rust, you might see something like

let message_reader = capnp::serialize::read_message(&mut stream, options)?;
let my_list = message_reader.get_root::<my_pointer_list_type::Reader>()?;

// Potentially dangerous operation
let sublist = my_list.get(attacker_controlled_index); // Out-of-bounds risk!

The underlying bug isn’t in *your* code, but in the Cap’n Proto implementation’s unchecked internal logic.

Let’s walk through a basic "conceptual" exploit

1. Craft a message: An attacker creates a Cap’n Proto message with a list-of-pointer type, but omits some or all of the underlying data, violating the expected structure.

Send to victim: The message is delivered to the vulnerable server or application.

3. Trigger vulnerable action: The app, while processing this list (for example, accessing myList[5]), uses Cap’n Proto’s functions that fail to correctly check list boundaries.
4. Result: The library reads past the end of allocated memory, possibly returning pointers into unrelated memory.

C++: Use at least one of .7.1, .8.1, .9.2, or .10.3.

- Rust: Use at least one of .13.7, .14.11, or .15.2 (from crates.io).

After updating, fully rebuild your application as code is often inlined.

Do not delay!  
If your Cap’n Proto-powered application is reachable by untrusted parties, this is a critical update. Even internal RPC services could be at risk if your perimeter is breached.

Conclusion

CVE-2022-46149 shows how tricky input validation and "list-of-list" handling can be dangerous, even in modern serialization libraries. Out-of-bounds reads can lead to either a crash or catastrophic data leaks. Thankfully, the Cap’n Proto maintainers responded quickly — but the fix goes beyond a simple library upgrade: you *must* rebuild your code due to inlined, templated functions.

Follow the official advisories:

- C++ GHSA-qfrc-7v3r-94xq
 - Rust GHSA-9v88-j6v9-qwgh
 - Cap’n Proto Blog

Stay patched, stay safe!

*References:*
- CVE-2022-46149 — NVD Entry
- Cap’n Proto Security Advisory (C++)
- Cap’n Proto Rust Security Advisory


*This long-read is an original summary for developers, security teams, and users of Cap’n Proto.*

Timeline

Published on: 11/30/2022 17:15:00 UTC
Last modified on: 02/10/2023 18:49:00 UTC