Koenkk / Koenkk/zigbee2mqtt

mqtt.user and mqtt.password secret references are expanded to plaintext in configuration.yaml on restart (network_key is preserved)

Open
#32,982 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

problem
Dominant language
TypeScript
Stars
15.7k
Forks
2k
Avg merge
18h 55m
Merged PRs (30d)
35

Description

What happened?

When mqtt.user and mqtt.password are defined with the documented '!secret.yaml ' syntax, Zigbee2MQTT replaces them with their plaintext values in configuration.yaml on every restart.

The same mechanism works correctly for advanced.network_key, which keeps its reference across restarts. Only the mqtt section is affected.

Before restart (configuration.yaml):

yaml

mqtt:
  base_topic: zigbee2mqtt
  server: mqtt://core-mosquitto:1883
  user: '!secret.yaml mqtt_user'
  password: '!secret.yaml mqtt_password'
advanced:
  network_key: '!secret.yaml network_key'
  enable_external_js: false

After restart:

yaml

mqtt:
  base_topic: zigbee2mqtt
  server: mqtt://core-mosquitto:1883
  user: my_actual_user            # <- expanded
  password: my_actual_password    # <- expanded
advanced:
  network_key: '!secret.yaml network_key'   # <- preserved, as expected
  enable_external_js: false                 # <- preserved

secret.yaml itself is left untouched and still holds the correct values.

Additional observation. If the key referenced from configuration.yaml does not exist in secret.yaml (e.g. '!secret.yaml password' while the file defines mqtt_password), Zigbee2MQTT creates the missing key in secret.yaml with the in-memory value, and expands the reference to plaintext in configuration.yaml. So the write-back path is partially aware of the secret file, yet still inlines the value in the main file.

This looks related to (and is the mirror image of) #26943, where secret.yaml gets overwritten with the reference strings themselves.

What did you expect to happen?

configuration.yaml should keep the '!secret.yaml ' references after a restart, as it does for advanced.network_key, and as described in the documentation:

The Securing the installation page explicitly recommends this mechanism to avoid storing credentials in plaintext, so the current behaviour defeats a documented security recommendation.

How to reproduce it (minimal and precise)
  1. Stop Zigbee2MQTT (important: editing while running gets overwritten from memory anyway).
  2. Create secret.yaml next to configuration.yaml:
yaml
mqtt_user: my_user
mqtt_password: my_password
network_key: [ ... your key ... ]
  1. Edit configuration.yaml:
yaml
mqtt:
  user: '!secret.yaml mqtt_user'
  password: '!secret.yaml mqtt_password'
advanced:
  network_key: '!secret.yaml network_key'
  1. Start Zigbee2MQTT.
  2. Reopen configuration.yaml: mqtt.user and mqtt.password are in plaintext, advanced.network_key still holds its reference.
Zigbee2MQTT version

2.13.0-1 (Home Assistant add-on)

Adapter firmware version

Revision: 8.0.2 [GA]

Adapter

SMLIGHT SLZB-06Mg24 (EFR32MG24), ember driver, TCP connection

Setup

Home Assistant add-on on Home Assistant OS 18.2 (HA Green, aarch64), Home Assistant Core 2026.8.3.

Device database.db entry

No response

Debug log

Not applicable — the issue is reproducible purely from the configuration file contents before and after a restart.

Notes

this is a re-report of #27077 (opened 2025-04-11 against 2.2.1-1, auto-closed as stale without investigation). The behaviour is unchanged in 2.13.0-1. The new element compared to that report is that advanced.network_key is preserved while the mqtt section is not, which should help narrow down the write-back code path.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal restart reproduction in the issue and trace the configuration write-back path for mqtt.user and mqtt.password, comparing it with advanced.network_key handling. Done means the !secret.yaml references remain in configuration.yaml after restart, secret.yaml remains correct, and a regression test covers the existing-key case.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend, security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.