CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-5W5R-MF82-595P

When 'Safe' Rust Walks the Plank: Cap'n Proto Undefined Behavior Deep Dive

Alon Barad
Alon Barad
Software Engineer

Jan 29, 2026·6 min read·33 visits

Executive Summary (TL;DR)

The Cap'n Proto Rust crate exposed public fields in `constant::Reader` and `StructSchema` that allowed safe code to inject arbitrary data. This data was subsequently processed by internal `unchecked` functions, leading to Undefined Behavior (UB).

A critical undefined behavior vulnerability in the Rust implementation of Cap'n Proto allows safe code to trigger memory corruption. By exposing internal raw pointers and unchecked offsets through public struct fields, the library violated Rust's safety guarantees, turning malformed schema constants into potential remote code execution or denial of service vectors.

The Hook: Infinity Times Faster, Zero Times Safer?

Cap'n Proto markets itself as "infinity times faster" than Protocol Buffers because it doesn't just serialize data; it lays it out in memory exactly as it will be sent over the wire. Zero encoding, zero decoding. It's a raw memory mapping dream. In C++, this is business as usual—you manage the pointers, you take the risk. But this is the Rust implementation we're talking about.

The promise of Rust is simple: if you don't write the word unsafe, you shouldn't be able to segfault. The compiler is the bouncer, and it checks everyone's ID. But in version 0.23 and below, the capnproto crate left the back door unlocked. It allowed "Safe" Rust code to construct objects that violated internal invariants, handing them off to performance-critical code that assumed everything was kosher. The result? A perfectly valid-looking Rust program that can corrupt memory, read out of bounds, or crash spectacularly.

The Flaw: Trusting the Public Interface

The vulnerability boils down to a classic API design blunder: exposing raw internals that the library logic implicitly trusts. In Cap'n Proto, performance is king, so internal functions often use unchecked operations to skip bounds checks. For example, PointerReader::get_root_unchecked assumes that the pointer logic it's about to perform is valid because it relies on the data having been validated during creation.

The problem? The structs holding that data—specifically constant::Reader and RawStructSchema—had their fields marked as pub. This meant any downstream developer (or attacker writing a plugin) could manually instantiate these structs. You didn't need a valid Cap'n Proto schema; you just needed to fill a struct with garbage data.

Because the fields were public, the library had no way to enforce invariants at construction time. When the user later called a safe method like .get(), the library took that user-supplied garbage, assumed it was a valid memory map, and passed it to get_root_unchecked. It’s like handing a loaded gun to a toddler because you assumed only a trained soldier would ever walk into the armory.

The Code: The Smoking Gun

Let's look at the code that allowed this mutiny. In src/constant.rs, the Reader struct was defined like this:

// The Vulnerable Definition
pub struct Reader<T> {
    #[doc(hidden)]
    pub phantom: PhantomData<T>,
 
    #[doc(hidden)]
    pub words: &'static [crate::Word],
}

See that pub words? That is the root of all evil here. Even though it is hidden from documentation, it is accessible to code. A user can create a Reader with a slice of words pointing to 0xDEADBEEF or random offsets.

The fix in version 0.24.0 is a lesson in Rust encapsulation. The developers locked down the visibility and forced the use of an unsafe constructor, shifting the burden of safety back to the developer:

// The Fixed Definition
pub struct Reader<T> {
    pub(crate) phantom: PhantomData<T>,
    pub(crate) words: &'static [crate::Word], // No longer public!
}
 
impl<T> Reader<T> {
    // You want to build this manually? You sign the waiver.
    pub const unsafe fn new(words: &'static [crate::Word]) -> Self {
        Self {
            phantom: PhantomData,
            words,
        }
    }
}

By marking the constructor unsafe, the library now complies with Rust's safety contract. If you pass bad data and it segfaults, it's your fault, not the library's.

The Exploit: Manufacturing Madness

Exploiting this doesn't require complex heap feng shui or ROP chains; it just requires writing "Safe" Rust that lies. An attacker works within the bounds of the language syntax but violates the semantic expectations of the library.

Here is a conceptual Proof of Concept showing how to trigger Undefined Behavior without using a single unsafe block in the attacking code (prior to the patch):

use capnp::constant;
use core::marker::PhantomData;
 
fn main() {
    // 1. Create a slice of 'words' that represent a garbage pointer.
    // In Cap'n Proto, specific bit patterns represent offsets.
    // We fake a pointer that points way out of bounds.
    let malicious_words = &[capnp::word(0xFFFFFFFF, 0xFFFFFFFF)];
 
    // 2. Manually construct the Reader using the public fields.
    // The compiler allows this because 'words' was public.
    let reader: constant::Reader<some_type::Owned> = constant::Reader {
        phantom: PhantomData,
        words: malicious_words,
    };
 
    // 3. Trigger the UB.
    // .get() calls internal unchecked functions.
    // The library tries to follow the 0xFFFFFFFF offset and reads invalid memory.
    let _ = reader.get(); 
}

When reader.get() executes, the application will likely crash (SIGSEGV) or, worse, read sensitive memory adjacent to the buffer if the offset is carefully calculated. In a scenario where schemas are dynamically loaded or defined by untrusted plugins, this allows a complete bypass of memory safety.

The Impact: Why Panic?

In the Rust ecosystem, a vulnerability labeled "Undefined Behavior in Safe Code" is the highest tier of defect. It erodes the trust model of the entire dependency tree. If capnproto is used in a network service (its primary use case), and that service processes user-supplied schema definitions or constants, an attacker can crash the node trivially.

While this specific vector requires the ability to construct the Reader or Schema object (which is often done at compile time via capnpc), systems that use dynamic schema loading or plugin architectures are vulnerable. The impact ranges from Denial of Service (DoS) via panic/segfault to potential information disclosure if the out-of-bounds read returns valid memory regions to the attacker.

The Fix: Safe Harbors

Remediation is straightforward but requires code changes. Upgrade to capnproto version 0.24.0 immediately. If you were manually constructing these structs (which you shouldn't have been doing, you naughty developer), your build will break.

You will need to switch to using the generated code from capnpc or, if you absolutely must create these manually, wrap your creation logic in an unsafe block and use the new Reader::new() constructor. This explicitly acknowledges that you have verified the input data.

For security teams auditing Rust codebases: Grep for direct struct initialization of capnp::constant::Reader or capnp::introspect::RawStructSchema. If you see them being built with curly braces { ... } rather than a constructor method, you are looking at vulnerable code.

Official Patches

Cap'n Proto (Rust)Commit fixing constant::Reader visibility
Cap'n Proto (Rust)Commit fixing RawStructSchema visibility

Fix Analysis (2)

Technical Appendix

CVSS Score
Critical/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Rust applications using capnproto < 0.24.0Systems using dynamic Cap'n Proto schema loading

Affected Versions Detail

Product
Affected Versions
Fixed Version
capnproto (Rust)
Cap'n Proto
< 0.24.00.24.0
AttributeDetail
Attack VectorLocal / Context-dependent
ImpactMemory Corruption / Undefined Behavior
CWEsCWE-242, CWE-822, CWE-119
StatusPatched in 0.24.0
LanguageRust
Bug ClassUnsound API / Safe Wrapper around Unsafe

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1203Exploitation for Client Execution
Execution
CWE-242
Use of Inherently Dangerous Function

The application allows the use of inherently dangerous functions by exposing internal memory structures to safe code, leading to untrusted pointer dereferences.

Known Exploits & Detection

ManualConstructing Reader with invalid words slice in safe code triggers UB

Vulnerability Timeline

Fix commits pushed by David Renshaw
2025-12-24
GHSA Advisory Published
2026-01-28

References & Sources

  • [1]GHSA-5W5R-MF82-595P
  • [2]RustSec Advisory

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•39 minutes ago•CVE-2026-48507
7.1

CVE-2026-48507: Incorrect Authorization in Snipe-IT Bulk User Edit and Merge Features

An incorrect authorization vulnerability (CWE-863) in Snipe-IT versions prior to 8.6.0 allows authenticated, low-privileged users with granular 'users.edit' permissions to modify restricted user flags ('activated' and 'ldap_import') and merge high-privileged administrator accounts into standard user accounts. This allows an attacker to lock administrators out of the system or completely hijack administrator accounts.

Amit Schendel
Amit Schendel
0 views•8 min read
•about 1 hour ago•GHSA-W2J7-F3C6-G8CW
4.7

GHSA-w2j7-f3c6-g8cw: Open Redirect Bypass via Parser Differential in Flask-Security

An open redirect vulnerability exists in Flask-Security versions up to and including 5.8.0. This flaw allows remote, unauthenticated attackers to perform open redirects by exploiting a parser differential between Python's standard library urlsplit() function and modern web browsers when subdomain redirection is allowed.

Amit Schendel
Amit Schendel
1 views•8 min read
•about 4 hours ago•CVE-2026-49205
6.5

CVE-2026-49205: Missing Authorization in phpMyFAQ Public REST API Write Endpoints

An incomplete security patch for CVE-2026-24421 in phpMyFAQ allows authenticated low-privileged users to bypass role-based access controls. While the initial patch addressed missing authorization in the BackupController, it left four critical write-enabled endpoints vulnerable. This allows remote attackers with a valid low-privilege API token to perform unauthorized data modifications, creating categories, creating FAQs, updating FAQs, and injecting questions directly into the database.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 13 hours ago•GHSA-74P7-6H78-GW8P
8.6

GHSA-74P7-6H78-GW8P: Multiple Critical Security Flaws in skillctl Agent-Skill Manager

An in-depth security audit of the skillctl command-line package manager revealed five critical and high-severity security vulnerabilities. The identified flaws span parameter-level command argument injection via the source_sha parameter, uncontrolled resource consumption (Denial of Service) through unnamed UNIX FIFOs and character devices, directory path traversal in the destination argument, commit-message trailer forgery via newline injection in skill names, and local credential exfiltration leveraging UNIX hardlinks. These vulnerabilities represent significant vectors for workstation compromise when executing agentic tasks in repositories containing untrusted files or pull requests. Remediation was introduced in version v0.1.3.

Alon Barad
Alon Barad
6 views•6 min read
•about 17 hours ago•CVE-2026-48153
8.5

CVE-2026-48153: Server-Side Request Forgery in Budibase OAuth2 SDK

CVE-2026-48153 is a Server-Side Request Forgery (SSRF) vulnerability in the Budibase OAuth2 SDK prior to version 3.39.0. It allows authenticated low-privileged users to bypass outbound network security blacklists and send arbitrary requests to internal subnets or cloud metadata services.

Alon Barad
Alon Barad
10 views•7 min read
•about 18 hours ago•GHSA-GHMH-JHMJ-WCMF
5.1

GHSA-GHMH-JHMJ-WCMF: Plaintext Storage of Enrollment Tokens at Rest in SQLite in nebula-mesh

The self-hosted Slack Nebula VPN control plane, nebula-mesh, stored high-privilege enrollment tokens in plaintext inside its SQLite database. This flaw allowed any adversary with read access to the database to retrieve pending tokens and enroll unauthorized hosts into the secure VPN mesh.

Alon Barad
Alon Barad
6 views•8 min read