Skip to content

Unauthenticated mesh source attribution lets any node spoof any NodeNum in the node DB #246

Description

@forkwright

Finding

The collector derives the observed node's identity directly from mesh_packet.from, a u32 field in an over-the-air Meshtastic frame, with no check against the cryptographic channel key or any out-of-band identity anchor. The from-derived node_num is then used unconditionally to insert or update the shared NodeDb entry. A node on the mesh can craft a packet with from set to any target NodeNum and overwrite that node's SNR, hop_count, and last_heard, including injecting entries for nodes never seen, and trigger the node_came_online flush path off raw packet attribution.

Evidence

crates/kerykeion/src/collector.rs:156

let node_num = NodeNum(mesh_packet.from);

Lines 164–181 use this node_num to upsert the node DB with no validation against the handshake-confirmed local node list or any channel authentication state, and the same path drives node_came_online.

Why this matters

Over-the-air Meshtastic frames from arbitrary nodes are the documented UNTRUSTED boundary. The node DB feeds topology, discovery decisions, and node_came_online message flushing. A spoofed from field lets an adversary (1) pollute SNR/hop telemetry for existing nodes, (2) drive node_came_online to flush queued messages toward an attacker-designated destination, and (3) seed entries for phantom nodes. The queue-flush manipulation in particular escalates a by-design attribution tradeoff into a message-redirection primitive against a target whose comms the adversary is trying to capture.

Desired correction

Guard the upsert: if mesh_packet.from == 0 or mesh_packet.from == 0xFFFF_FFFF (broadcast sentinel), skip the node DB update. Gate the node_came_online path on an explicit authenticated reachability/topology event rather than raw packet attribution, and document the residual trust acceptance for the remaining attribution. Done when: a packet with from == 0 or from == 0xFFFF_FFFF neither creates nor updates a node DB entry, and node_came_online fires only from an authenticated reachability event rather than raw from attribution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions