Skip to content

Security

Martin Gergeleit edited this page Apr 12, 2026 · 3 revisions

Security

This page gives an overview of the attack surface of the ESP32 NAT Router and recommends hardening measures for each deployment scenario.

Attack Surface Overview

The router exposes several management interfaces over the network. Understanding where each listens and what access it grants is the starting point for any hardening effort.

Interface Protocol Default port Auth Encryption Default state
Web UI HTTP/TCP 80 Optional password None (plaintext) Enabled
Remote Console TCP 2323 Optional password None (plaintext) Disabled
MCP Bridge TCP 3000 None None (plaintext) Disabled
PCAP stream UDP 19000 None None (plaintext) Off

Both the Web UI and the Remote Console carry credentials and full configuration in plaintext. Anyone who can reach the port can intercept passwords and configuration data or take over the device. Due to memory restrictions and required certificate handling TLS is not implemented. WireGuard is the light-weight alternative here.

Network Topology and Interface Exposure

By default, management interfaces listen on all active interfaces (AP, STA/ETH, VPN). In a typical deployment the interfaces have very different trust levels:

Internet ──────── STA/ETH (untrusted uplink)
                       │
                  ESP32 Router
                       │
AP clients ─────── AP (internal, semi-trusted)
                       │
VPN tunnel ──────── VPN (trusted, encrypted)

The AP interface is under your control and its clients are known devices. The STA/ETH uplink connects to infrastructure you do not own. The VPN tunnel is the safest channel because the transport itself is encrypted by WireGuard before it even reaches the router.

Recommendations by Scenario

Minimum: Set a Password

With no password set, the web interface and remote console (if enabled) are completely open to anyone who can reach them. Always set a password before exposing the router on a shared network:

set_router_password <strong-password>

This protects both the web UI and the remote console with the same credential. Use a strong, unique password — the credential is transmitted in plaintext so a short or reused password is easy to capture.

Home Network (Trusted Uplink)

Even on a home network the STA/ETH interface connects to equipment you do not fully control. Restrict management to the AP interface only:

Web UI:

web_ui bind ap

Remote Console (if used):

remote_console bind ap

This ensures that even if someone on the upstream network scans your IP, neither management port is reachable from that side.

Semi-Trusted Environment (Office, Shared WiFi)

Restrict management to the AP interface as above, and additionally set a strong password. Consider disabling the remote console entirely if you do not need it:

remote_console disable

If the AP itself serves untrusted clients (e.g. IoT devices or guests), consider restricting management to VPN only (see below) so that AP clients cannot reach the configuration interface either.

Untrusted / Public Network

In hostile environments (public WiFi, hotel networks, conference networks) the only safe option is to route management traffic through the WireGuard VPN tunnel:

Web UI — VPN only:

web_ui bind vpn

Remote Console — VPN only:

remote_console bind vpn

With these settings the router rejects HTTP and console connections arriving on the STA and AP interfaces. You can only reach the management interface after your client machine has an active WireGuard connection to the same VPN server.

To lock out AP clients as well, use vpn as the only allowed interface for both services.

Maximum Hardening: Disable Web UI

For production deployments where you configure once and then leave the device running, the safest option is to disable the web interface entirely after initial setup:

web_ui disable

All parameters can still be changed via the serial console or the remote console (if enabled and bound to a trusted interface). Re-enable with:

web_ui enable

Using the Firewall to Protect Management Ports

The ACL firewall can add a second layer of protection independent of the interface-bind settings. The to_ap ACL controls traffic arriving from AP clients toward the router itself, and to_esp controls traffic arriving from the uplink.

Block web UI access from AP clients (port 80):

acl add to_ap TCP any * 192.168.4.1 80 deny

Block remote console from the uplink:

acl add to_esp TCP any * any 2323 deny

Allow management only from a specific trusted client:

acl add to_ap TCP 192.168.4.100 * 192.168.4.1 80 allow
acl add to_ap TCP any * 192.168.4.1 80 deny

ACL rules are evaluated in order; the first match wins. A deny rule without a preceding allow drops all matching traffic regardless of the interface-bind settings — the two mechanisms are independent and complementary.

See Firewall for the full ACL reference.

WireGuard as a Secure Management Channel

Binding management interfaces to the VPN interface and routing your admin machine through the same VPN server gives you:

  • Encrypted transport: WireGuard uses ChaCha20-Poly1305; credentials and configuration are not readable in transit.
  • Authentication at the transport layer: Only peers with a valid key pair can establish the tunnel.
  • No open ports on the uplink: From the perspective of the public network the only visible traffic is WireGuard UDP (port 51820 by default).

Setup steps:

  1. Configure WireGuard with your VPN server as the peer.
  2. Connect your admin machine to the same VPN server.
  3. Set web_ui bind vpn and remote_console bind vpn.
  4. Access the router at its VPN tunnel IP (e.g. http://10.0.0.2).

See WireGuard VPN for detailed VPN configuration.

Config Export Security

The config export (/api/config-export) downloads a JSON file containing all router settings including WiFi passwords and WireGuard keys.

Encrypted Export (recommended)

Enter a passphrase in the Passphrase field before clicking Write Config. The file is then an opaque JSON envelope — the payload is encrypted with XChaCha20-Poly1305 and the key is derived from your passphrase using PBKDF2-HMAC-SHA256 with 10 000 iterations and a random 16-byte salt. A different salt and nonce are generated for every export, so two exports of the same config with the same passphrase produce different files.

The Poly1305 authentication tag means any tampering with the file is detected on import: a wrong passphrase or a modified ciphertext causes the import to be rejected before any settings are written.

Encrypted exports include the WireGuard private key and PSK, making them suitable as a complete backup. Encrypted files are safe to store in cloud storage or send over untrusted channels. The passphrase is never stored on the device.

Plain Export

If no passphrase is entered the file is plain JSON. The following secrets are intentionally omitted from plain exports: STA WiFi password, AP WiFi password, WireGuard private key, and WireGuard PSK. The remaining settings (SSIDs, IPs, ACL rules, port maps, etc.) are exported in cleartext. Treat the file like sensitive configuration material:

  • Do not store it in shared drives, cloud storage, or version control.
  • Delete it after use.
  • Transmit only over encrypted channels (e.g. through a WireGuard-protected connection to the router).

The export endpoint is protected by the web UI password (if set) and subject to the same interface-bind restrictions as all other management operations.

PCAP and MCP Bridge

The PCAP stream (port 19000/UDP) carries raw packet data with no authentication. It is only active when explicitly enabled and always disabled after reboot. Once enabled, disable it when not used any more:

pcap off

The MCP Bridge (port 3000/TCP) provides full programmatic control of the router with no authentication. It is a separate binary and should only be started on isolated or VPN-only networks.

Credential Storage

Passwords are stored as salted SHA-256 hashes in NVS. WiFi credentials and WireGuard keys are stored as plaintext strings in NVS. Physical access to the device (serial console or flash read) grants access to these stored credentials. For high-security deployments, use ESP32's flash encryption and secure boot.

NVS is not erased by re-flashing the firmware. To wipe all stored credentials:

esptool.py -p /dev/ttyUSB0 erase_flash

Summary Checklist

Step Command / Action
Set a strong password set_router_password <password>
Encrypt config exports Enter a passphrase in the Web UI before exporting
Restrict web UI to AP only (home) web_ui bind ap
Restrict web UI to VPN only (untrusted) web_ui bind vpn
Restrict remote console similarly remote_console bind ap or remote_console bind vpn
Disable remote console if not needed remote_console disable
Disable web UI after initial config web_ui disable
Add ACL rules for defense in depth acl add to_esp TCP any * any 2323 deny
Disable PCAP when not in use (default off) pcap off
Don't use the MCP Bridge on an unsave network Don't start/install Python code
Erase NVS before decommissioning esptool.py erase_flash

Clone this wiki locally