Summary
The Meshtastic firmware (starting from version 2.5) introduces asymmetric encryption (PKI) for direct messages, but when the pki_encrypted flag is missing, the firmware silently falls back to legacy AES-256-CTR channel encryption. This was an intentional decision to maintain backwards compatibility. However, the end-user applications, like Web app, iOS/Android app, and applications built on top of Meshtastic using the SDK, did not have a way to differentiate between end-to-end encrypted DMs and the legacy DMs.
This creates a downgrade attack path where adversaries who know a shared channel key can craft and inject spoofed direct messages that are displayed as if they were PKC encrypted. Users are not given any feedback of whether a direct message was decrypted with PKI or with legacy symmetric encryption, undermining the expected security guarantees of the PKI rollout.
Details
When the firmware receives a direct message over LoRa or MQTT on numport 4 TEXT_MESSAGE_APP:
- If the the firmware decrypts the payload using the node’s asymmetric PKI keys, the
pki_encrypted flag in the MeshPacket is set to true.
- If the asymmetric decryption fails, the firmware falls back to legacy AES-256-CTR decryption using the symmetric channel key, and If the
pki_encrypted flag remains set to false.
This fallback mechanism allows attackers who know the symmetric channel key (which is shared by all members of a channel, and trivially known in the case of default/public channels) to craft spoofed direct messages:
- Encrypt the message payload using the channel’s symmetric AES-256-CTR key.
- Injects the crafted packet over LoRa or MQTT.
The receiving node will accept and display the message as a valid direct message. On-device user interfaces (e.g., OLED displays, MUI) do not differentiate between PKI and legacy decryption, giving the recipient no way to verify the authenticity of the message.
This effectively enables a downgrade attack, where the security of direct messages can be bypassed by forcing legacy encryption.
The decision of whether a DM was decrypted with PKI or legacy encryption is left to the UI, with the flag pki_encrypted. This means legacy DMs can appear as secure PKI messages if UI does not implement safe handling. A safer design would be for the firmware to enforce PKI by default and only allow legacy DMs if explicitly enabled for known legacy nodes.
The fix in 2.7.15 was to disallow legacy DMs at the firmware level.
PoC
- Create a channel where the victim node is present.
- Craft a MeshPacket addressed to the victim node without setting the
pki_encrypted flag.
- Encrypt a TEXT_MESSAGE_APP payload with the known AES-256-CTR channel key.
- Send the packet via LoRa or MQTT.
- Observe that the victim’s firmware decrypts and accepts the message as a direct message, with no on-device indication that legacy encryption was used.
Impact
Type: Downgrade Attack / Spoofing / Identity Impersonation
Affected: All Meshtastic firmware users (>= v2.5 and < v2.7.15) relying on PKI for direct message security.
Severity: Moderate – Enables detectable spoofing of direct messages, and breaks PKI security guarantees and allowing impersonation of any node.
Exploitability: Trivial on public/default channels with widely known keys.
Summary
The Meshtastic firmware (starting from version 2.5) introduces asymmetric encryption (PKI) for direct messages, but when the
pki_encryptedflag is missing, the firmware silently falls back to legacy AES-256-CTR channel encryption. This was an intentional decision to maintain backwards compatibility. However, the end-user applications, like Web app, iOS/Android app, and applications built on top of Meshtastic using the SDK, did not have a way to differentiate between end-to-end encrypted DMs and the legacy DMs.This creates a downgrade attack path where adversaries who know a shared channel key can craft and inject spoofed direct messages that are displayed as if they were PKC encrypted. Users are not given any feedback of whether a direct message was decrypted with PKI or with legacy symmetric encryption, undermining the expected security guarantees of the PKI rollout.
Details
When the firmware receives a direct message over LoRa or MQTT on numport 4
TEXT_MESSAGE_APP:pki_encryptedflag in the MeshPacket is set to true.pki_encryptedflag remains set to false.This fallback mechanism allows attackers who know the symmetric channel key (which is shared by all members of a channel, and trivially known in the case of default/public channels) to craft spoofed direct messages:
The receiving node will accept and display the message as a valid direct message. On-device user interfaces (e.g., OLED displays, MUI) do not differentiate between PKI and legacy decryption, giving the recipient no way to verify the authenticity of the message.
This effectively enables a downgrade attack, where the security of direct messages can be bypassed by forcing legacy encryption.
The decision of whether a DM was decrypted with PKI or legacy encryption is left to the UI, with the flag
pki_encrypted. This means legacy DMs can appear as secure PKI messages if UI does not implement safe handling. A safer design would be for the firmware to enforce PKI by default and only allow legacy DMs if explicitly enabled for known legacy nodes.The fix in 2.7.15 was to disallow legacy DMs at the firmware level.
PoC
pki_encryptedflag.Impact
Type: Downgrade Attack / Spoofing / Identity Impersonation
Affected: All Meshtastic firmware users (>= v2.5 and < v2.7.15) relying on PKI for direct message security.
Severity: Moderate – Enables detectable spoofing of direct messages, and breaks PKI security guarantees and allowing impersonation of any node.
Exploitability: Trivial on public/default channels with widely known keys.