Serialization 11 📄 CBOR (RFC 8949) — Concise Binary Object Representation
CBOR is a binary serialization format standardized in RFC 8949, designed to encode the same data model as JSON—maps, arrays, integers, strings, booleans, and null—in a compact binary form . It occupies a specific position in the binary format landscape: more expressive than MessagePack because it includes native tags for dates, big numbers, and typed arrays, but less schema-driven than Protobuf because it carries its own type information in every value. Its adoption is concentrated in constrained environments (IoT, COSE, CWT) where payload size and parser footprint matter, and in systems that need deterministic encoding for cryptographic verification.
This chapter covers CBOR’s major type system, the deterministic encoding profiles that make it suitable for consensus and signatures, and the security considerations that arise from its variable-length encoding. The sections that follow walk through the format’s structure, its performance characteristics, and the use cases where it is the correct choice.
Key point: CBOR is a self-describing binary format with a small eight-type core and an extensible tag system; its variable-length encoding enables compactness, but deterministic encoding profiles (CDE) are required when byte-identical output matters for signatures or consensus.
a. The major type system and encoding structure
CBOR defines eight major types, each identified by the upper three bits of the initial byte. The lower five bits carry the “additional information” that determines how the argument is encoded .
| Major Type | Meaning | Content |
|---|---|---|
| 0 | Unsigned integer | Value directly or in following bytes |
| 1 | Negative integer | −1 − N |
| 2 | Byte string | N bytes of arbitrary data |
| 3 | Text string | N bytes of UTF-8 |
| 4 | Array | N data items |
| 5 | Map | 2N data items (key-value pairs) |
| 6 | Tag | Tag number N, one data item follows |
| 7 | Simple/float | Booleans, null, floats, break code |
The additional information value determines the argument’s width. Values 0–23 encode the argument directly in the initial byte. Values 24, 25, 26, and 27 indicate that the argument follows in 1, 2, 4, or 8 bytes respectively. Value 31 signals an indefinite-length item, terminated by a “break” stop code (major type 7, additional information 31) .
# Integer 42: major type 0, additional info 24, followed by 0x2A
18 2A
# Text string "hello": major type 3, additional info 5
65 68 65 6C 6C 6F
# Array of 2 items: major type 4, additional info 2
82 [item1] [item2]
# Map of 1 pair: major type 5, additional info 1
A1 [key] [value]
The indefinite-length encoding is CBOR’s streaming mechanism. An array can begin before its element count is known, and the encoder writes the break code when it is done . This is useful for constrained devices that cannot buffer the entire structure before sending it, but it means the same logical data can have multiple valid encodings.
b. Deterministic encoding and the CDE profile
CBOR’s flexibility is a problem for cryptographic systems. The same data can be encoded in multiple ways: integers can use the shortest or longest representation, maps can order their keys arbitrarily, and floats can use half, single, or double precision. RFC 8949 defines “deterministic encoding” rules to eliminate this variability, and the CBOR Common Deterministic Encoding Profile (CDE) formalizes them for interoperability .
The CDE requirements include: integers use the shortest possible encoding, maps are sorted in a defined order, and floating-point values use the preferred representation that accurately represents the value . The IEEE study on blockchain-enabled networks found that CBOR achieved 100% byte-identical encoding across 10,000 independent trials when deterministic encoding was used, satisfying the determinism requirement for distributed consensus .
# Deterministic: shortest integer encoding
42 → 18 2A (not 19 00 2A or 1A 00 00 00 2A)
# Non-deterministic map ordering (invalid for CDE)
A2 61 62 01 61 61 02 # {b: 1, a: 2}
# CDE requires sorted keys: {a: 2, b: 1}
The determinism requirement is why CBOR is used in COSE (CBOR Object Signing and Encryption) and CWT (CBOR Web Tokens). A signature is computed over the encoded bytes; if the same logical message can encode to different bytes, the signature verification fails or becomes ambiguous. The CDE profile ensures that a given data structure has exactly one valid encoding.
c. Performance, size, and security
The measured performance of CBOR places it in the same class as MessagePack, both faster and smaller than JSON but larger than schema-driven Protobuf for repeated structured records. The IEEE blockchain study found that CBOR and MessagePack incur 144 bytes of first-call container allocation and then zero incremental per-message allocation, compared to JSON’s 528–1,104 bytes per-message allocation . A C++ benchmark from December 2025 found CBOR’s message size for a complex nested object was 560 bytes, compared to JSON’s 616 bytes, MessagePack’s 545 bytes, and Protobuf’s 344 bytes .
The size advantage is not universal. The IEEE web study found that CBOR can be larger than JSON for numeric-heavy data because its default encoder uses 8-byte double-precision floats, while JSON’s textual representation of small decimals can be shorter . The same study found that CBOR saves an average of 15.2 kBytes (18.8% gain) per JSON object from the HTTP Archive, with a maximum savings of 7.6 MBytes (80.0% gain) . The conclusion is that CBOR’s benefit depends on the data’s shape: byte strings and integers benefit, floats can suffer.
The security record of CBOR libraries is mixed. The Python cbor2 library had two vulnerabilities in its C extension decoder (CVE-2025-64076): an integer underflow leading to out-of-bounds reads in decode_definite_long_string, and a memory leak from missing reference count releases. Both could be exploited remotely with crafted CBOR containing multi-byte UTF-8 characters at 65,536-byte chunk boundaries, causing denial of service through crashes or memory exhaustion. The vulnerabilities were fixed in version 5.7.1 . A separate issue (CVE-2025-68131) affected decoder reuse: values marked with the shareable tag persisted in memory and could be accessed by subsequent messages using the sharedref tag, allowing data leakage across trust boundaries when a decoder instance was reused. Fixed in 5.8.0 .
The pattern is the same as other binary formats: the decoder must be treated as an attack surface, the library must be patched, and untrusted input must not be decoded with a reused decoder that carries state across trust boundaries.
Complete Example Session
# ============================================
# PART 1: CBOR ENCODING OF A SIMPLE MAP
# ============================================
# JSON: {"id": 42, "name": "widget", "active": true}
#
# CBOR bytes:
# A3 # map, 3 pairs
# 62 69 64 # text "id"
# 18 2A # unsigned 42
# 64 6E 61 6D 65 # text "name"
# 66 77 69 64 67 65 74 # text "widget"
# 66 61 63 74 69 76 65 # text "active"
# F5 # simple true
# ============================================
# PART 2: BYTE STRING ADVANTAGE
# ============================================
# JSON: {"data": "SGVsbG8="} (base64 text)
# CBOR: A1 64 64 61 74 61 45 48 65 6C 6C 6F
# map, "data", byte string (5 bytes "Hello")
# Byte strings avoid base64 inflation (33% overhead)
# ============================================
# PART 3: DETERMINISTIC ENCODING
# ============================================
# Same data, multiple encodings:
# 42 → 18 2A (preferred)
# 42 → 19 00 2A (non-preferred, longer)
# CDE requires the preferred form
# ============================================
# PART 4: SECURITY RULE
# ============================================
# CVE-2025-64076: crafted long strings at chunk boundaries
# Fix: upgrade cbor2 >= 5.7.1
# CVE-2025-68131: decoder reuse leaks shared values
# Fix: upgrade cbor2 >= 5.8.0, do not reuse decoders across trust boundaries
The parts covered the map encoding, the byte string advantage over base64, the deterministic encoding requirement, and the security rules for the cbor2 library.
Quick Reference
Major Types
| Type | Meaning | Example |
|---|---|---|
| 0 | Unsigned int | 18 2A = 42 |
| 1 | Negative int | 20 = −1 |
| 2 | Byte string | 45 48 65 6C 6C 6F = “Hello” |
| 3 | Text string | 65 68 65 6C 6C 6F = “hello” |
| 4 | Array | 82 [a] [b] |
| 5 | Map | A1 [key] [value] |
| 6 | Tag | C1 1A ... (epoch date) |
| 7 | Simple/float | F5 = true, F4 = false |
Deterministic Encoding (CDE)
| Rule | Detail |
|---|---|
| Integers | Shortest encoding |
| Maps | Sorted keys |
| Floats | Preferred representation |
| Purpose | Byte-identical output for signatures |
Performance (Complex Nested Object)
| Format | Size | Notes |
|---|---|---|
| JSON | 616 B | Baseline |
| MessagePack | 545 B | Smallest |
| CBOR | 560 B | |
| Protobuf | 344 B | Schema-driven |
Security CVEs (cbor2)
| CVE | Issue | Fixed |
|---|---|---|
| CVE-2025-64076 | Integer underflow, memory leak in long strings | 5.7.1 |
| CVE-2025-68131 | Decoder reuse leaks shared values | 5.8.0 |
Best Practices
✅ Do This:
# Use CBOR where byte strings or tags matter
# (IoT payloads, COSE, CWT) # ✅
# Use deterministic encoding for signatures/consensus
# (CDE profile) # ✅
# Upgrade cbor2 to >= 5.8.0
pip install --upgrade cbor2 # ✅
# Do not reuse decoders across trust boundaries
# (CVE-2025-68131 pattern) # ✅
❌ Don’t Do This:
# Use CBOR for float-heavy data without checking size
# (8-byte floats can be larger than JSON text) # ❌
# Assume all CBOR encodings are deterministic
# (variable-length encoding, map ordering) # ❌
# Decode untrusted CBOR with an unpatched cbor2
# (CVE-2025-64076) # ❌
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Signature fails on re-encoded data | Non-deterministic encoding | Use CDE profile |
| Decoder crashes on long strings | CVE-2025-64076 | Upgrade to 5.7.1+ |
| Data leaks between messages | Decoder reuse (CVE-2025-68131) | Upgrade to 5.8.0, new decoder per trust boundary |
| Larger than JSON for floats | Default 8-byte encoding | Use smaller float width or check data shape |
Real-World Examples
1. Integer 42
18 2A
2. Text string “hello”
65 68 65 6C 6C 6F
3. Byte string
45 48 65 6C 6C 6F # "Hello"
4. Map with 2 pairs
A2 [key1] [val1] [key2] [val2]
5. Simple true
F5
6. COSE_Sign1
D2 84 43 A1 01 26 ... # tagged COSE structure
7. Deterministic map
# Keys sorted before encoding
8. Indefinite array
9F [items...] FF # start, items, break
9. Upgrade cbor2
pip install "cbor2>=5.8.0"
10. IoT payload
Compact CBOR with byte strings for sensor data
Visual
CBOR Major Types
┌─────────────────────────────────────────────────────────┐
│ INITIAL BYTE │
│ ┌──────────────────────────────────────────┐ │
│ │ 7 6 5 │ 4 3 2 1 0 │ │
│ │ major │ additional info │ │
│ └──────────────────────────────────────────┘ │
│ │
│ Major 0: unsigned int │
│ Major 1: negative int │
│ Major 2: byte string │
│ Major 3: text string │
│ Major 4: array │
│ Major 5: map │
│ Major 6: tag │
│ Major 7: simple/float │
└─────────────────────────────────────────────────────────┘
Deterministic Encoding
┌─────────────────────────────────────────────────────────┐
│ SAME DATA, MULTIPLE ENCODINGS │
│ │
│ 42 → 18 2A (preferred, 2 bytes) │
│ 42 → 19 00 2A (3 bytes, valid but non-preferred) │
│ │
│ CDE requires the preferred form │
│ Signature computed over bytes │
│ Non-deterministic encoding breaks verification │
└─────────────────────────────────────────────────────────┘
Size Comparison
┌─────────────────────────────────────────────────────────┐
│ COMPLEX NESTED OBJECT │
│ │
│ Protobuf ████████████ 344 B │
│ MessagePack ██████████████████ 545 B │
│ CBOR ███████████████████ 560 B │
│ JSON █████████████████████ 616 B │
│ │
│ Schema-driven Protobuf wins; CBOR beats JSON │
└─────────────────────────────────────────────────────────┘
Security Boundary
┌─────────────────────────────────────────────────────────┐
│ DECODER REUSE │
│ │
│ Message A (trusted) │
│ → decoder stores shareable value │
│ │
│ Message B (untrusted) │
│ → sharedref tag reads A's value │
│ │
│ CVE-2025-68131: data leak across trust boundaries │
│ Fix: new decoder per boundary, upgrade to 5.8.0 │
└─────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Standard | RFC 8949 (STD 94) |
| Major types | 8 (int, neg int, bytes, text, array, map, tag, simple) |
| Indefinite length | 0x9F start, 0xFF break |
| Deterministic profile | CDE (sorted maps, shortest ints) |
| Size vs JSON | 18.8% average savings |
| Size vs Protobuf | Larger for repeated records |
| Security CVEs | cbor2 < 5.8.0 (decoder reuse) |
Key takeaways:
- CBOR encodes JSON’s data model with eight major types and a tag system. It adds byte strings, tags for dates and big numbers, and indefinite-length streaming—features JSON lacks .
- Deterministic encoding is required for cryptographic use. The CDE profile mandates shortest integer encoding, sorted map keys, and preferred float representation so that the same data has exactly one valid byte sequence .
- CBOR is smaller than JSON but larger than Protobuf. The 18.8% average savings over JSON comes from removing quotes and using binary integers; Protobuf’s field-number encoding is more compact for repeated structured records .
- The cbor2 library had serious decoder vulnerabilities. CVE-2025-64076 (integer underflow and memory leak) and CVE-2025-68131 (decoder reuse data leak) require upgrading to 5.8.0 or later .
- CBOR is the substrate for COSE, CWT, and WebAuthn. The compact binary format is what makes signatures and tokens small enough for constrained devices, and the determinism profile makes them verifiable .
Remember: CBOR is JSON’s data model in binary, with the additions that constrained environments need: byte strings for binary data, tags for semantic types, and streaming for devices that cannot buffer. Its variable-length encoding makes it compact, but that same variability is why deterministic profiles exist—a signature over non-deterministic encoding is ambiguous. Use CBOR where its byte-string and tag features matter, use the CDE profile where bytes must be reproducible, and treat the decoder as an attack surface, because it is.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!