Skip to content

Security

The Security Manager component provides 4 tools for auditing device security posture, checking flash encryption status, and reading or burning eFuse values. These tools wrap esptool and espefuse CLI commands as async subprocesses.


Perform a comprehensive security audit of a connected ESP device. Gathers chip identity, flash encryption status, secure boot state, JTAG status, and eFuse summary into a single structured report.

NameTypeDefaultDescription
portstr | NoneNoneSerial port or socket:// URI. Required.
result = await client.call_tool("esp_security_audit", {
"port": "/dev/ttyUSB0"
})
{
"success": true,
"port": "/dev/ttyUSB0",
"chip_id": "0x00f01d83",
"security_info": {
"Secure Boot": "disabled",
"Flash Encryption": "disabled"
},
"efuse_summary": {
"MAC": "aa:bb:cc:dd:ee:ff",
"FLASH_CRYPT_CNT": "0",
"ABS_DONE_0": "0",
"JTAG_DISABLE": "0"
},
"security_fuses": {
"FLASH_CRYPT_CNT": "0",
"ABS_DONE_0": "0",
"JTAG_DISABLE": "0"
},
"posture": {
"flash_encryption": "disabled",
"secure_boot": "disabled",
"jtag": "enabled (vulnerable)"
}
}

The posture object provides a quick summary of the three primary security mechanisms. The security_fuses object contains the raw eFuse values for the following security-relevant fields:

eFuseControls
FLASH_CRYPT_CNTFlash encryption enable/disable counter
ABS_DONE_0Secure Boot v1 permanent enable
ABS_DONE_1Secure Boot v2 permanent enable
JTAG_DISABLEJTAG debug interface disable
DISABLE_DL_ENCRYPTDisable flash encryption in download mode
DISABLE_DL_DECRYPTDisable flash decryption in download mode
DISABLE_DL_CACHEDisable flash cache in download mode
FLASH_CRYPT_CONFIGFlash encryption configuration

Check the current flash encryption status and provide guidance on enabling it. This tool reads the relevant eFuses but does not perform the actual burn — use esp_efuse_burn for that.

NameTypeDefaultDescription
portstr | NoneNoneSerial port or socket:// URI. Required.
key_filestr | NoneNonePath to an encryption key file. Stored in the response for reference only.
result = await client.call_tool("esp_enable_flash_encryption", {
"port": "/dev/ttyUSB0"
})

When encryption is not enabled:

{
"success": true,
"port": "/dev/ttyUSB0",
"flash_encryption_enabled": false,
"FLASH_CRYPT_CNT": "0",
"FLASH_CRYPT_CONFIG": "0",
"message": "Flash encryption is NOT enabled. To enable, you need to: 1) Generate or provide an encryption key, 2) Burn FLASH_CRYPT_CNT and FLASH_CRYPT_CONFIG eFuses, 3) Flash encrypted firmware. WARNING: This is irreversible on real hardware. Test on QEMU first."
}

When encryption is already active:

{
"success": true,
"port": "/dev/ttyUSB0",
"flash_encryption_enabled": true,
"FLASH_CRYPT_CNT": "1",
"FLASH_CRYPT_CONFIG": "0xf",
"message": "Flash encryption is already enabled on this device."
}

Read eFuse values from a device. Without a specific efuse_name, returns the full human-readable summary from espefuse summary. With efuse_name, returns just that field’s value.

eFuses are one-time-programmable bits that control chip security, MAC address, calibration data, and more. Reading is non-destructive.

NameTypeDefaultDescription
portstr | NoneNoneSerial port or socket:// URI. Required.
efuse_namestr | NoneNoneSpecific eFuse to read (e.g., "MAC", "FLASH_CRYPT_CNT"). Returns full summary if omitted.
result = await client.call_tool("esp_efuse_read", {
"port": "/dev/ttyUSB0"
})

Full summary:

{
"success": true,
"port": "/dev/ttyUSB0",
"efuses": {
"MAC": "aa:bb:cc:dd:ee:ff",
"FLASH_CRYPT_CNT": "0",
"ABS_DONE_0": "0",
"JTAG_DISABLE": "0",
"ADC_VREF": "1100"
},
"raw_output": "EFUSE_NAME (BLOCK0) Description = value R/W (hex)\n..."
}

Specific eFuse:

{
"success": true,
"port": "/dev/ttyUSB0",
"efuse_name": "MAC",
"value": "aa:bb:cc:dd:ee:ff"
}

When a requested eFuse is not found, the response includes the list of available names:

{
"success": false,
"error": "eFuse 'NONEXISTENT' not found",
"available_efuses": ["MAC", "FLASH_CRYPT_CNT", "ABS_DONE_0", "..."],
"port": "/dev/ttyUSB0"
}

Permanently program an eFuse bit field on the device. This operation is irreversible on real hardware. The tool reads the eFuse value before and after the burn to confirm the change.

Uses espefuse burn-efuse with the --do-not-confirm flag because confirmation is handled at the MCP client level.

NameTypeDefaultDescription
efuse_namestr(required)Name of the eFuse to burn (e.g., "JTAG_DISABLE").
valuestr(required)Value to burn (e.g., "1", "0x1").
portstr | NoneNoneSerial port or socket:// URI. Required.
NameEffect
JTAG_DISABLEPermanently disables JTAG debugging interface
FLASH_CRYPT_CNTEnables flash encryption (odd bit count = encrypted)
ABS_DONE_0Permanently enables Secure Boot v1
DISABLE_DL_ENCRYPTDisables flash encryption in UART download mode
DISABLE_DL_DECRYPTDisables flash decryption in UART download mode
DISABLE_DL_CACHEDisables flash cache in UART download mode
# Disable JTAG on a QEMU device (safe to test)
result = await client.call_tool("esp_efuse_burn", {
"efuse_name": "JTAG_DISABLE",
"value": "1",
"port": "socket://localhost:5555"
})
{
"success": true,
"port": "socket://localhost:5555",
"efuse_name": "JTAG_DISABLE",
"value_requested": "1",
"value_before": "0",
"value_after": "1",
"warning": "eFuse burn is IRREVERSIBLE on real hardware"
}