
Every interface, protocol and memory region in an embedded system is a potential entry point for an attacker. Understanding the embedded system attack surface starts with understanding the architecture itself: how hardware layers, firmware, memory types, debug interfaces and communication protocols connect and where each one introduces exploitable exposure. This article works through all of those layers systematically, from the physical hardware up to wireless communication protocols, with concrete examples of what attackers target at each level and what you can do about it.
An embedded system is not a single monolithic piece of software running on hardware. It is a stack of interdependent layers, each with its own components, its own attack exposure and its own set of defensive controls. Before you can reason about the embedded system attack surface of any device, you need a clear mental model of that stack.
From bottom to top, the architecture looks like this:
Each layer inherits the vulnerabilities of the layers below it and adds its own. A weakness in the bootloader can undermine every security control in the application. A misconfigured wireless interface can bypass every hardware-level protection you built into the silicon. Mapping the attack surface means auditing every layer independently and then auditing the trust boundaries between layers.
The choice of processor determines the hardware security features available to your design. Not all microcontrollers are equal from a security standpoint, and treating them as interchangeable leads to designs where you are compensating in software for features the hardware should be providing.
The security-relevant features to look for when selecting a microcontroller include:
GPIO pins are the device’s electrical boundary with the outside world. Every GPIO that is accessible on a connector, test point or header is a potential attack path. Attack scenarios involving GPIO include:
None of these attacks require expensive equipment. A Raspberry Pi Pico, a few resistors and an open-source tool like ChipWhisperer-Lite can perform voltage and clock glitching against many common microcontrollers for under $100 of hardware cost.
Firmware is the permanent software stored on the device that controls how the hardware behaves. It is executed directly from flash storage on bare-metal systems, or loaded into RAM and executed from there on systems with an MMU (Memory Management Unit). Unlike application software on a general-purpose OS, firmware typically has no privilege separation: a bug anywhere in the firmware can affect the entire device.
The boot sequence is a critical attack window. On a device without secure boot, an attacker who can write to flash (via a JTAG interface, a vulnerable OTA update handler, or a compromised update server) can replace the bootloader or application firmware with a backdoored version. The device then boots normally from the user’s perspective while executing attacker-controlled code.
A secure boot chain works by verifying each stage before executing it:
Each link in this chain must be verified. A secure boot implementation that verifies the application but not the first-stage bootloader can be bypassed by replacing the first-stage bootloader with code that skips the application verification step.
Where an RTOS is present, the scheduler, interrupt service routines and system calls all represent trust boundaries. A task running at a lower privilege level should not be able to read memory belonging to a higher-privilege task. Without an MPU configured correctly, this isolation does not exist in practice even if the RTOS architecture intends it.
Application layer code typically handles:
Each of these activities is a vulnerability site. Parsing external input without length validation causes buffer overflows. Writing to persistent storage without integrity checks allows an attacker to modify stored configuration data between power cycles.
Unprotected memory is where most embedded secrets leak. Every memory type in an embedded system has different security properties, and most devices are deployed with the default configuration, which prioritises accessibility over protection.
Flash stores your firmware and often your configuration data. Its security-relevant properties:
RAM holds your runtime state: stack frames, heap allocations, global variables and any secrets that have been decrypted for use. RAM is volatile, meaning it loses its contents when power is removed. However:
ROM contains the immutable bootloader code. OTP regions store configuration bits, including the root public key used for secure boot verification and the eFuse bits that enable security features. These are write-once: once a security feature is enabled, it cannot be disabled.
This is both a strength and a risk. The strength is that an attacker cannot disable secure boot by modifying OTP over a software interface. The risk is that a mistake in production programming, such as burning the wrong public key or setting an OTP bit incorrectly, bricks the device permanently. Production OTP programming procedures must be validated on engineering samples before production run.
EEPROM stores device configuration: network credentials, calibration data, user settings, device certificates. It is frequently overlooked during security reviews. Common weaknesses:
At minimum, compute and store an HMAC (Hash-based Message Authentication Code) over all configuration data using a device-unique key, and verify the HMAC on every boot before trusting the stored values.
Peripheral interfaces are the wiring between your processor and the rest of the hardware on your PCB: sensors, displays, external flash, radio modules and power management ICs. They are also a significant attack surface because they carry real data, including decrypted sensor readings, over unprotected copper traces that can be probed with nothing more than test clips and a logic analyzer.
UART is the most common peripheral interface used for debug output and serial consoles on embedded devices. During development, UART typically provides a root shell, verbose debug logging and direct hardware access. In production, UART is frequently left enabled because disabling it requires a deliberate step that many teams skip under time pressure.
An attacker who connects to an exposed UART header with a $3 USB-to-serial adapter can often:
The fix is to disable UART output in production builds and, where UART must remain active for operational reasons, implement authentication before any command execution is permitted.
SPI is a synchronous serial protocol used for high-speed communication with external flash chips, display controllers, ADCs (Analog to Digital Converters) and radio modules. Because SPI carries unencrypted data in most implementations, probing the SPI bus between a processor and an external SPI flash chip yields the raw firmware image, bypassing any read protection set in the processor’s internal flash controller.
Where possible, use microcontrollers with internal flash rather than external SPI flash for firmware storage. When external SPI flash is unavoidable, enable flash encryption at the processor level so that data on the SPI bus is ciphertext, not plaintext.
I2C is a two-wire bus used to connect multiple devices to a single processor: temperature sensors, accelerometers, EEPROMs and real-time clock ICs are common I2C devices. I2C has no built-in authentication. Any device on the bus can address any other device. An attacker who taps the I2C bus can read all sensor data and inject spoofed sensor readings by acting as a master on the bus.
USB is bidirectional and carries complex protocol stacks. USB attack surfaces include:
Hardware debug interfaces are the primary physical attack path against embedded systems. They were designed to give engineers complete control over the processor during development: reading and writing memory, setting breakpoints, single-stepping through code and examining register state. All of those capabilities are equally useful to an attacker.
JTAG is a four or five-pin interface (TCK, TDI, TDO, TMS and optionally TRST) present on virtually every embedded processor. With JTAG access and an inexpensive adapter (OpenOCD with a $5 FTDI-based adapter, or a JLink for $18), an attacker can:
JTAG access points are frequently exposed as unpopulated headers on production PCBs, as clearly labeled test points accessible after removing a device enclosure, or as footprints that can be identified from the PCB silkscreen. Security researchers routinely find JTAG headers on commercial IoT devices within five minutes of opening the enclosure.
SWD is ARM’s two-pin alternative to JTAG (SWDCLK and SWDIO). It provides the same debugging and memory access capabilities as JTAG on ARM Cortex-M devices and requires even fewer pins to expose. The same attack tools that support JTAG (OpenOCD, pyOCD, JLink) support SWD with no additional configuration.
Protecting against JTAG and SWD attacks requires action at both the PCB level and the firmware level:
# Verify STM32 flash read protection level using OpenOCD
# Connect via JTAG/SWD adapter first, then run:
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg \
-c "init; flash read_bank 0 rdp_check.bin 0x1FFFF800 4; exit"
# Read the first byte: 0xAA = Level 0 (open), 0xBB = Level 1 (read-protected)
xxd rdp_check.bin | head -1
# To SET read protection to Level 1 in OpenOCD (irreversible path to Level 2):
# openocd -f interface/stlink.cfg -f target/stm32f1x.cfg \
# -c "init; stm32f1x option_write 0 0xFFFFF8BB; reset; exit"
Most microcontrollers have a hardware bootloader burned into ROM that activates when a specific pin is held high or low at startup (BOOT0 on STM32, GPIO0 on ESP32). This bootloader accepts firmware images over UART, USB or SPI and typically does no signature verification. If an attacker can hold the boot pin in the correct state (easily done by probing the PCB), they can reflash the device with arbitrary firmware regardless of any OTA authentication you have implemented in software.
Mitigations: In production firmware, check the boot configuration register and immediately reconfigure boot pins using software remapping if hardware bootloader mode must be accessible. For devices where hardware bootloader access must be permanently blocked, use OTP bits to disable it (where supported by the silicon).
Not all attacks require physical access. Many embedded devices expose logical access paths over the network that provide a remote entry point into the device and, through it, into the local network or the cloud infrastructure the device communicates with.
Embedded web interfaces are a consistent source of vulnerabilities in consumer and industrial devices. Common weaknesses found in the wild include:
system("ping " + user_input) is trivially exploitable.IoT devices that communicate with cloud backends introduce an API attack surface. Weaknesses here include: API keys hardcoded in firmware (extractable via binwalk and strings); no certificate pinning on TLS connections (enabling MITM interception with a proxy); overly broad API permissions (a single device token that authorises access to all devices in an account); and no rate limiting on authentication endpoints (enabling brute-force credential attacks against the cloud backend).
Companion apps for embedded devices often handle Bluetooth pairing, WiFi credential provisioning and remote control. They extend the attack surface significantly because:
Wired interfaces are not inherently more secure than wireless. They simply require the attacker to have physical access to the cable or network rather than being within radio range.
Ethernet-connected embedded devices are typically directly addressable over the local network. The attack surface includes all open TCP and UDP ports, the management web interface, Telnet or SSH services and any network-exposed APIs. Default configurations frequently leave Telnet open on port 23, providing an unencrypted remote shell with no rate limiting on authentication attempts.
CAN (Controller Area Network) bus is the backbone of automotive and some industrial embedded networks. Its security properties are poor by modern standards: there is no source authentication (any node can transmit as any other node’s ID), no encryption, no message sequence numbers and no replay protection. Every ECU on a CAN bus can read every message on that bus. Injecting a malicious CAN frame requires only that an attacker connect a CAN transceiver to the bus, which is achievable through an OBD-II port in under 10 seconds.
The automotive industry is addressing this with Autosar SecOC (Secure Onboard Communication), which adds a CMAC (Cipher-based MAC) and a freshness counter to CAN messages, providing authentication and replay protection without changing the underlying CAN physical layer.
Modbus, Profibus and DNP3 (Distributed Network Protocol 3) were designed for isolated industrial networks in an era before internet connectivity. They have no authentication, no encryption and no concept of trust levels between nodes. When SCADA (Supervisory Control and Data Acquisition) systems that use these protocols are connected to enterprise networks or the internet through improperly configured firewalls, the entire OT (Operational Technology) network becomes reachable from the internet with no credential barrier.
Wireless interfaces extend the attack surface beyond physical reach. An attacker does not need to touch your device if they can reach it over radio.
WiFi on an embedded device inherits all the vulnerabilities of WiFi in general, plus some specific to constrained implementations. Common issues:
BLE is widely used for device provisioning, control and telemetry in consumer IoT. Its attack surface includes:
Zigbee is used extensively in smart home and industrial mesh networks. Its security is based on a 128-bit AES network key shared across all devices in the network. The key distribution mechanism during device join is the vulnerability: in many implementations the network key is transmitted in plaintext during the join process, visible to any Zigbee sniffer. An attacker with a $30 USB Zigbee coordinator running Zigbee2MQTT can capture the network key and subsequently decrypt all network traffic.
LoRa is used for long-range, low-power IoT deployments in smart agriculture, smart metering and asset tracking. LoRaWAN provides AES-based encryption by default, which is better than most wireless protocols at this power level. Remaining attack surfaces include: replay attacks against devices with no frame counter validation; over-the-air activation (OTAA) key provisioning exposure; and gateway-level attacks where a compromised gateway can modify or drop packets for all devices it serves.
Cellular connectivity provides the broadest geographic attack surface because the device is addressable from anywhere on the internet. Attack vectors include: direct attacks against open ports on the device’s public IP address; attacks against the device management platform via compromised SIM credentials; and IMSI (International Mobile Subscriber Identity) catchers that capture device identity by impersonating a legitimate cell tower.
Regardless of the specific protocol, communication attacks against embedded systems fall into four categories. Every communication design decision should be evaluated against all four.
Passive capture of unencrypted traffic. The attacker learns credentials, device state, commands and any sensitive data the device transmits. Defence: encrypt all communications using an authenticated cipher such as AES-GCM or ChaCha20-Poly1305. Encryption without authentication (such as AES-CBC without a MAC) prevents eavesdropping but not the next category.
The attacker intercepts traffic between two parties, reading and potentially modifying it while both parties believe they are communicating directly. Defence: mutual TLS with certificate pinning (the device validates the server certificate against a stored CA (Certificate Authority) certificate and the server validates the device certificate). Without certificate pinning, TLS prevents passive eavesdropping but a MITM attacker can present a different valid certificate and the device will accept it.
/* Verifying a server certificate hash in embedded TLS (mbedTLS example)
This pins the server to a specific certificate fingerprint,
rejecting any other certificate even if it is signed by a trusted CA */
#include "mbedtls/ssl.h"
#include "mbedtls/x509_crt.h"
/* SHA-256 fingerprint of the expected server certificate */
static const unsigned char SERVER_CERT_HASH[32] = {
0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6, 0x07, 0x18,
/* ... remaining 24 bytes of the SHA-256 fingerprint ... */
};
int verify_server_cert(void *data, mbedtls_x509_crt *crt,
int depth, uint32_t *flags) {
unsigned char hash[32];
if (depth != 0) return 0; /* Only check leaf certificate */
/* Compute SHA-256 of the DER-encoded certificate */
mbedtls_sha256(crt->raw.p, crt->raw.len, hash, 0);
/* Compare against pinned fingerprint */
if (memcmp(hash, SERVER_CERT_HASH, 32) != 0) {
*flags |= MBEDTLS_X509_BADCERT_OTHER;
return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED;
}
return 0;
}
The attacker captures a legitimate message and retransmits it later to trigger the same action again. A captured “unlock door” command retransmitted 24 hours later should be rejected. Defence: include a nonce (number used once) or sequence counter in every authenticated message. The receiver tracks seen nonces and rejects any message with a previously seen value. The HMAC or digital signature must cover the nonce so an attacker cannot modify it.
Wireless jamming floods the radio channel with noise, preventing legitimate communication. This is trivially achievable against WiFi, BLE and Zigbee using inexpensive SDR (Software Defined Radio) hardware. Against safety-critical devices, the design must assume communication may be unavailable for extended periods and fail safely in that condition rather than waiting indefinitely for a command that never arrives.
Attack surface mapping is the structured process of identifying all entry points on a device and evaluating the risk at each one. Doing this systematically before design freeze is far cheaper than finding vulnerabilities in the field.
The process has three steps:
List every interface that allows input into the device or output from it. This should be exhaustive. Work from the hardware datasheet, the PCB layout, the firmware source and the network configuration. A useful template:
| Interface | Type | Accessible From | Authentication Required | Encrypted |
|---|---|---|---|---|
| JTAG header J5 | Physical / Debug | PCB (requires enclosure removal) | No | No |
| UART0 (TX/RX) | Physical / Serial | PCB test point TP12 | No | No |
| WiFi AP (provisioning) | Wireless | Radio range (~50m) | No (open AP) | No |
| BLE GATT service | Wireless | Radio range (~10m) | Just Works pairing | Yes (after pairing) |
| HTTP management port 80 | Network | Local LAN | Password (default: admin) | No |
| MQTT broker port 1883 | Network | Internet (if firewall open) | Username/password | No (plain MQTT) |
| OTA update endpoint | Network / Cloud | Internet | Device token | HTTPS |
| SPI flash chip U4 | Physical / Bus | PCB (probe pads) | No | No |
For each entry point, assess how easily an attacker can reach it. Score the accessibility on three dimensions:
For each entry point, ask what an attacker achieves by compromising it. Using the four categories from Section 1 (confidentiality, integrity, availability and physical consequences), assign an impact rating. Multiply likelihood by impact to produce a risk priority score. Address high-risk items before releasing the design.
Attack surface reduction is not about achieving zero exposure. Every useful feature adds some exposure. The goal is to eliminate unnecessary exposure and harden the exposure that remains.
UART debug output, JTAG access, development web endpoints, test credentials, verbose logging and diagnostic modes all belong in development builds, not production firmware. Use compile-time flags to strip them from production builds completely, not just to hide them behind an undocumented command.
/* Compile-time removal of debug UART output in production builds
In your build system, define PRODUCTION_BUILD=1 for release firmware
This ensures zero runtime overhead and zero exposure, not just suppression */
#ifdef PRODUCTION_BUILD
#define DEBUG_PRINT(fmt, ...) do {} while(0) /* Compiled out entirely */
#else
#define DEBUG_PRINT(fmt, ...) printf("[DBG] " fmt "\n", ##__VA_ARGS__)
#endif
/* Usage in firmware: */
DEBUG_PRINT("Boot complete, heap free: %d bytes", esp_get_free_heap_size());
/* In production builds, the above line generates zero machine code */
On production PCBs: depopulate JTAG and UART headers. Fill or cover test point vias with solder mask. Use tamper-evident enclosure seals. Apply flash read protection in the factory programming step and verify it as part of the production test fixture. Make re-enabling debug access as difficult as possible.
No management interface, API endpoint, MQTT broker connection or BLE GATT characteristic should be accessible without authentication. Default credentials must be unique per device (generated at factory time, not hardcoded) and must be forced to change on first use. Rate limit authentication endpoints to prevent brute-force attacks.
All communications carrying credentials, commands, sensor data or configuration must use an authenticated encryption scheme. Use TLS 1.2 or 1.3 for TCP-based protocols, DTLS 1.2 for UDP-based protocols, and MQTT over TLS (port 8883) rather than plain MQTT (port 1883). Pin the server certificate or CA certificate in firmware to prevent MITM attacks using other valid certificates.
Every firmware image delivered via OTA must be signed by a private key held securely by the manufacturer. The device must verify the signature before applying the update. A compromised OTA update mechanism is the most effective path to mass-compromise of a deployed device fleet because it requires no physical access and scales to every device simultaneously.
Attack surfaces grow over time as new features are added and configurations drift. Schedule a security review of the attack surface map at every major firmware release. Engage external researchers through a vulnerability disclosure policy so that discoveries are reported to you before they are published or sold.
The embedded system attack surface spans every layer of the architecture: physical hardware and GPIO pins accessible to glitching attacks, memory regions that leak secrets when left unprotected, peripheral buses that carry plaintext data across probeable PCB traces, debug interfaces that hand full device control to anyone with a $5 adapter and open network ports, and wireless interfaces accessible to anyone within radio range. Mapping that surface systematically using the enumeration and risk-scoring process described here, then reducing it by disabling unused interfaces, locking debug access before shipping, enforcing authentication everywhere and signing all firmware updates, is the foundation that every other embedded security control depends on. No encryption algorithm, no RTOS privilege model and no cloud-side access control provides meaningful protection if the attacker can reach the hardware layer and bypass all of them.






