Skip to content

Authentication-transparent DDS bridge extensions: auth bytes silently stripped at CDR schema boundary #59

Description

@cleitonaugusto

Summary

Any authentication material appended after a typed DDS/CDR payload is silently
stripped at CDR deserialization — by standard subscribers, bridges, and RMW
implementations. This is the same structural flaw as MAVLink relay-stripping
(CVE pending, GHSA-f5rj-mrxh-r7vm), adapted to the DDS type system.

Root Cause

CDR deserialization reads exactly the bytes defined by the IDL type schema.
Bytes appended after the schema boundary are never transferred into the typed
struct. Re-serialization produces schema-size bytes only. Auth material gone.

Two failure modes depending on RMW:

Middleware Effect
CycloneDDS 11.0.1 Auth bytes arrive in raw RTPS payload, discarded at CDR deserialization — silent strip
FastDDS / rmw_fastrtps_cpp Reader history pre-allocated to type max CDR size; oversized payloads rejected — sample never reaches callback

The silent-strip case is worse: the subscriber receives a valid message with no
indication that auth material was attached and removed.

Tested Configuration

CycloneDDS 11.0.1 Python bindings
FastDDS (rmw_fastrtps_cpp) — ROS2 Humble default RMW
geometry_msgs/msg/Twist (52-byte CDR: 4B header + 6×float64)
Ubuntu 22.04 LTS, ROS2 Humble, Python 3.10

PoC Output (--simulate mode, no ROS2 install required)

Auth scheme                     Sent  Received   Stripped  Result
────────────────────────────  ──────  ────────  ─────────  ────────────────
HMAC-SHA3-256 (32 B)              84        52         32  FAIL — auth gone
Ed25519 sig  (64 B)             116        52         64  FAIL — auth gone
ML-DSA-87 sig (4627 B)         4679        52       4627  FAIL — auth gone

PoC: tools/ros2_bridge_strip_poc.py in https://github.com/cleitonaugusto/CleitonQ

Run with --simulate (no ROS2 install) or against real CycloneDDS endpoints.

Multi-hop Compounding

Multi-domain deployments using domain_bridge, ros1_bridge, or zenoh-bridge-ros2dds
re-serialize at each hop. Auth bytes stripped at hop 1 cannot be recovered at hop 2+.

Comparison with MAVLink

Protocol Boundary marker Strip mechanism
MAVLink v2 STX + LEN frame header Relay reads exactly those bytes, discards rest
ROS2/DDS CDR IDL type schema Deserializer reads schema fields only, ignores trailing bytes

Same vulnerability class. Different boundary marker. Both protocol implementations
are correct per their respective specs — the flaw is in the architectural
assumption that bytes appended outside a typed boundary survive to the application.

The Fix

Authentication material must be a separate, typed ROS2 message on a parallel topic.

Example:

  • /cmd_vel — geometry_msgs/Twist (command)
  • /cmd_vel/auth — cleitonq_msgs/Auth (ML-DSA-87 sig + nonce, typed)

The subscriber verifies /cmd_vel/auth before acting on /cmd_vel.

DDS middleware forwards typed messages as-is — their byte boundary is defined
by their own schema, not appended to another message.

Related


I am Cleiton Augusto Correa Bezerra, who found and documented the MAVLink variant
of this vulnerability class. The DDS/ROS2 variant follows the same architectural
root cause. Happy to provide additional test data or collaborate on a mitigation proposal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions