What a read hides#
A viewer can read the whole configuration tree, and that tree contains WireGuard
private keys, IPsec pre-shared secrets and password hashes. Ten read endpoints are
therefore wrapped in redactSecrets, which replaces the value of any known secret leaf
with the literal string [redacted] for a principal below a stated role.
{
"interfaces": {
"wireguard": {
"wg0": {
"address": "10.0.0.1/24",
"private-key": "[redacted]",
"peer": {"laptop": {"public-key": "kZ…="}}
}
}
}
}public-key is left alone. The match is on whole field names, not substrings.
The endpoints that wear it#
| Endpoint | Redacted below |
|---|---|
GET /api/config | admin |
GET /api/config/commands | admin |
GET /api/vpn/ipsec | admin |
GET /api/vpn/openvpn | admin |
GET /api/wireguard | admin, and for every role a tunnel's private key and a peer's pre-shared key |
GET /api/drift | admin |
GET /api/pki | admin |
GET /api/history/diff | admin |
GET /api/fleet/{id}/config | admin |
GET /api/staged | operator |
/api/pki returns the pki configuration subtree as well as the show pki tables, and
that subtree holds private key material beside the certificates. Below admin those key
values are blanked like any other secret leaf.
/api/staged redacts below operator rather than below admin. An operator sees the
key they have just added to the pending changes; a viewer does not.
/api/wireguard withholds a tunnel's private key and every peer's pre-shared key from
every role, administrators included: the WireGuard page is given each tunnel's public key
instead, and writes a pre-shared key without reading it back.
Keys the agent generates#
A WireGuard tunnel's private key, an OpenVPN client's private key and an OpenVPN TLS key
can be generated by the agent. Such a key is sealed when it is staged: the agent keeps
a digest of it, and /api/staged, the answer to /api/stage, and the audit entries for a
commit or a discard carry [redacted] in its place for every role, admin included. The
router receives it when the change is applied. From then on it is in the configuration
like any other key: /api/config shows it to an admin.
GET /api/config/raw is not in this list. It is the whole-configuration download,
secrets included — the backup export — so instead of being redacted it is
admin-only.
The leaf names#
Fifteen names, matched case-insensitively and with surrounding quotes stripped:
private-key pre-shared-key pre-shared-secret
preshared-key psk plaintext-password
encrypted-password password passphrase
shared-secret-key secret key
api-key auth-key authentication-keyRedaction keys on the leaf name, not on a path, so a leaf of one of these names is blanked wherever in the tree it appears.
Four of them are also ordinary English words#
key, secret, password and psk are unambiguous as leaf names and ambiguous loose
in a line of text. In text they are honoured only on a line that is plainly
configuration: one that starts with set or delete, or whose last field is quoted.
Otherwise the router's own message no key found would come back as
no key [redacted].
Two ways it is applied#
Only the response body is rewritten, and it is rewritten in one of two ways.
| The body is | What happens |
|---|---|
| Valid JSON | Decoded, walked, and re-encoded. Every map key that is a secret leaf has its value replaced, at any depth, inside arrays too. Every string value is additionally passed through the text rule below. |
| Anything else | Treated as text: line by line, field by field. |
The text rule replaces everything from the field after the secret name to the end of the line, preserving the line's indentation:
set interfaces wireguard wg0 private-key [redacted]What it does not do#
The one place the agent blanks a secret outside this wrapper is the settings endpoint:
GET /api/admin/settings clears the stored licence key before answering, and
PUT /api/admin/settings preserves it across a write.
Checking it on your own router#
# As a viewer:
curl -sk "$R/api/config?path=interfaces/wireguard" -H "Authorization: Bearer $VIEWER_TOKEN" \
| grep -o '"private-key":"[^"]*"'
# "private-key":"[redacted]"
# As an admin, the same call returns the key.See also#
- Role matrix — which role each endpoint compares against.
- Endpoint index — the Redacts column.
- Files and directories — where the secrets the API never returns actually live, with modes.
- Audit entries
- Roles and planes