element-hq / element-hq/element-web

In verification dialog, "Verify with Recovery Key or Phrase" does nothing if 4S secrets are encrypted with the wrong 4S key

Open
#29,553 6 comments 1 reaction 0 assignees View on GitHub
A-E2EE A-E2EE-Cross-Signing A-E2EE-Key-Backup O-Uncommon S-Major T-Defect
Dominant language
TypeScript
Stars
13.5k
Forks
2.8k
PR merge metrics
PR metrics pending

Description

[Updated 2025/07/07]

Given an account with:
* `m.megolm_backup.v1`, `m.cross_signing.master` encrypted with one 4S (recovery) key
* `m.secret_storage.default_key` set to another 4S key

Then, the verification dialog fails silently. It can be reached in any of the following ways:

Case 1:
* Sign in
* In verification modal, click "Verify with Recovery Key or Phrase"
* Nothing happens

Case 2:
* Sign in, and skip verification modal; alternatively, reload with an existing unverified session.
* Observe "Verify this session" toast
* Click "Verify"
* In verification modal, click "Verify with Recovery Key or Phrase"
* Nothing happens

Case 3 (possibly the same as case 1):
* Sign in, and skip "Verify" modal; alternatively, reload with an existing unverified session.
* "Settings" -> "Encryption". Observe "Device not verified".
* Click "Verify this device"
* Click "Verify with Recovery Key or Phrase"
* Nothing happens

The following error appears on the console:

```
Error: Request for non-default 4S key
at Object.getSecretStorageKey (SecurityManager.ts:122:15)
at async ServerSideSecretStorageImpl.getSecretStorageKey (secret-storage.ts:645:26)
at async ServerSideSecretStorageImpl.get (secret-storage.ts:598:37)
at async CrossSigningIdentity.bootstrapCrossSigning (CrossSigningIdentity.ts:53:44)
at async RustCrypto.bootstrapCrossSigning (rust-crypto.ts:738:9)
at async doAccessSecretStorage (SecurityManager.ts:279:13)
at async withSecretStorageKeyCache (SecurityManager.ts:191:16)
at async accessSecretStorage (SecurityManager.ts:233:5)
```

Previous symptoms, before #29088 and other fixes

Then, there are several flows that just fail silently, or with an unhelpful error message:

Case 1:
* Sign in
* In verification modal, click "Verify with Recovery Key or Phrase"
* Nothing happens

Case 2:
* Sign in, and skip verification modal; alternatively, reload with an existing unverified session.
* Observe "Set up Secure Backup" toast
* Click "Continue"
* Nothing happens

Case 3 (possibly the same as case 1):
* Sign in, and skip "Verify" modal; alternatively, reload with an existing unverified session.
* "Settings" -> "Encryption". Observe "Device not verified".
* Click "Verify this device"
* Click "Verify with Recovery Key or Phrase"
* Nothing happens

Case 4 (will be removed by https://github.com/element-hq/element-web/pull/29088):
* Sign in, and skip "Verify" modal; alternatively, reload with an existing unverified session.
* "Settings" -> "Security & Privacy" -> "Secure Backup" -> "Connect this session to Key Backup"
* Observe:
![Image](https://github.com/user-attachments/assets/ff0e68b1-a7ae-40d7-9df9-9e3638ae49b5)

Case 5 (will be removed by https://github.com/element-hq/element-web/pull/29088):
* Sign in, and skip "Verify" modal; alternatively, reload with an existing unverified session.
* "Settings" -> "Security & Privacy" -> "Cross-signing" -> "Set up Secure Backup"
* Nothing happens

In all cases, the following error appears on the console:

```
Error: Request for non-default 4S key
at Object.getSecretStorageKey (SecurityManager.ts:122:15)
at async ServerSideSecretStorageImpl.getSecretStorageKey (secret-storage.ts:645:26)
at async ServerSideSecretStorageImpl.get (secret-storage.ts:598:37)
at async CrossSigningIdentity.bootstrapCrossSigning (CrossSigningIdentity.ts:53:44)
at async RustCrypto.bootstrapCrossSigning (rust-crypto.ts:738:9)
at async doAccessSecretStorage (SecurityManager.ts:279:13)
at async withSecretStorageKeyCache (SecurityManager.ts:191:16)
at async accessSecretStorage (SecurityManager.ts:233:5)
```

## Workaround

Unless you have another device with working cross-signing and key storage, the only workaround is to perform a reset:

![Image](https://github.com/user-attachments/assets/8c91d4b8-3912-4828-9728-763109be04e7)

This will reset your message key history and replace your cryptographic identity, but there isn't much choice: the keys to that data have been lost.

## Root cause

There is a reasonable question to be asked about *how* the data got corrupted in this way.

The short answer is: a buggy implementation (probably a Matrix client) did it. With access to the homeserver logs *from the time the corruption occurred*, it's probably possible to figure out which client was responsible. The problem is, homeservers typically don't store logs for very long, and it's likely the corruption happened weeks, months, or even years ago.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the recovery-key verification flows described in the issue and follow the stack trace through SecurityManager.ts, secret-storage.ts, CrossSigningIdentity.ts, and rust-crypto.ts. Compare the handling of a non-default 4S key with the verification dialog’s failure path; done should include a visible, useful outcome instead of the current silent failure.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.