Skip to main content

Identity rotation

The most consequential alert this product produces. Read this page before you ever have to act on one.

What it means

The Edge signs every request to Cloud with an Ed25519 key derived from your mnemonic at m/83696968'/0'/0'. Cloud pins the public half on first sync.

If the identity Cloud sees stops matching the one it pinned, a different mnemonic is mounted. There is no other explanation. The identity is derived, not configured, so it cannot change while the seed stays the same.

Cloud's response is immediate and deliberate:

  1. Authentication fails before the payload is read401 EDGE_SIGNATURE_INVALID.
  2. Any new extended public keys are quarantined, not registered.
  3. The affected chains go amber (quarantined); address generation is blocked.
  4. identity_rotation_detected is delivered as a webhook, regardless of your subscription filter.
  5. Your account owner is paged by email.
  6. Further operations return 409 IDENTITY_ROTATION_PENDING.

The Edge signs with a key derived from the phrase; Cloud compares it with the pinned one. A mismatch quarantines the new keys, stops address generation and pages the owner; from there the two ways out are approve, with an owner and a fresh TOTP code, or reject, which changes nothing.

Why the gate exists

Addresses derive from the mnemonic. A different mnemonic derives different addresses.

If Cloud accepted the new identity silently, it would begin issuing addresses from the new keys to your existing customers — while deposits kept arriving at the old addresses, whose private keys your new Edge does not hold. Those funds would still be recoverable with the old phrase, and nobody would know they needed it until a customer complained.

This is the only decision in ChainOS that can orphan customer funds. That is why it requires an account owner and a fresh TOTP code rather than being a setting.

One thing it explicitly does not do: stop watching what you already have. Addresses derived from prior extended public keys stay monitored forever. Nothing already issued goes dark, whatever you decide.

Diagnose before you decide

Do not approve a rotation to clear an alert

Approving means "yes, this new mnemonic is the one I intend to use". If it is not — if a wrong secret got mounted — approving tells ChainOS to derive future addresses from a phrase you may not have a backup of.

Find the cause first. Every hour you spend diagnosing is an hour of blocked address generation, which is annoying. Approving the wrong phrase is permanent.

Did you intend to change the mnemonic?

If someone on your team deliberately rotated, and you have the new phrase backed up and tested, this is expected and you can proceed to approval.

If not, work through these

CauseHow to check
A wrong secret mountedCompare the mounted file against your secret manager. A stale Kubernetes secret in one namespace, or a Compose file pointing at the wrong path
A replica with a different mnemonicGET /v1/edge/sessions — look at podHint. In a fleet, one misconfigured replica does this while the others are fine
A sandbox phrase in a live deploymentCheck the API key prefix on that Edge. Also produces 409 CROSS_ENVIRONMENT_IDENTITY
A restored backup of the wrong vintageAn older secret-manager version containing a superseded phrase
A truncated or re-encoded secretA 0400 file with a trailing newline, or a base64 round-trip. The Edge validates the BIP-39 checksum, so this usually fails earlier — but a valid different phrase does not
Genuine compromiseNobody can account for the change. Treat as an incident

Confirm which phrase is mounted by checking what it derives. Do this in sandbox, not against live:

# Start a sandbox Edge with the suspect phrase and compare index 0.
curl -s "$EDGE/addresses?chain=btc&size=1" -H "X-API-Key: $CHAINOS_EDGE_KEY" \
| jq -r '.data.content[0] | [.derivationPath, .address] | @tsv'

Against your own record of the first address your live account issued. If they differ, the mounted phrase is not your live one.

Approving

Requires an account owner and a fresh TOTP code.

Console: Settings → Security → Pending rotations → Approve.

curl -X POST $CLOUD/v1/settings/rotations/{id}/approve \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "totp": "123456" }'

What happens:

  • The new identity is pinned.
  • The quarantined extended public keys are registered.
  • Readiness returns to green and address generation resumes — from the new keys.
  • Addresses from the previous keys stay monitored.

Rejecting

curl -X POST $CLOUD/v1/settings/rotations/{id}/reject \
-H "Authorization: Bearer $TOKEN" \
-d '{ "totp": "123456" }'

The quarantined keys are discarded and the previously pinned identity stands. Reject when the change was a mistake, then fix the deployment and restart the Edge with the correct phrase — Cloud will recognise the original identity and resume normally.

Rejecting is the safe default when you are unsure. It changes nothing and it is reversible; the rotation simply re-triggers on the next sync if the wrong phrase is still mounted.

After an approved rotation

Keep the old mnemonic. Permanently. It is the only key to funds at addresses already issued, including deposits that arrive at those addresses after the rotation. You are now running two sets of keys and that is not a temporary state — see Mnemonic management.

Then:

  • Sweep funds from old addresses into treasury using the old phrase, if you want to stop maintaining two key sets in practice. Note that new deposits to old addresses will keep arriving from customers who saved the address.
  • Decide whether to re-issue addresses. You do not have to. Old addresses keep working and stay monitored. Re-issuing means telling customers their deposit address changed, which is a support cost.
  • Export the address inventory so the old-key addresses are recorded outside ChainOS:
    curl -s "$EDGE/addresses?size=1000" -H "X-API-Key: $CHAINOS_EDGE_KEY" \
    | jq -r '.data.content[] | [.chain, .address, .derivationPath, .userRef] | @csv' \
    > addresses-pre-rotation.csv
  • Record the reason in your own change log. A rotation with no recorded cause is the thing an auditor will ask about.

If you suspect compromise

Treat as a security incident, not as a configuration problem.

  1. Reject the rotation. Do not approve an identity you cannot account for.
  2. Do not restart the Edge in a loop. Repeated authentication failures are noise on top of a signal you need.
  3. Revoke the Edge's API key — Settings → API keys — which cuts that Edge off from Cloud regardless of what it holds.
  4. Revoke the zkl_* local keys your application holds if the host itself is suspect.
  5. Assume the old mnemonic is compromised if the host was. Move funds using it, from a machine you trust, to addresses derived from a phrase generated fresh.
  6. Mail security@ziklagconsulting.com with the rotation id and the meta.requestId of a failing request.

Ziklag cannot move your funds on your behalf in any of these steps, including this one. That is the property that makes a Cloud-side compromise survivable and it is also the reason step 5 is yours to carry out.