openclaw - ✅(Solved) Fix Matrix E2EE: getSecretStorageKey callback not implemented — bots cannot bootstrap cross-signing [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#66171Fetched 2026-04-14 05:38:55
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1

Bot accounts using Matrix E2EE cannot decrypt inbound messages because the getSecretStorageKey callback is not implemented. Cross-signing bootstrap always fails, leaving the bot device permanently unverified.

Root Cause

The getSecretStorageKey callback is required by matrix-js-sdk to access or create SSSS (Server-Side Secret Storage), which stores master/self-signing/user-signing keys. Without it:

  1. No SSSS → no cross-signing keys published
  2. No cross-signing → Element marks device as unverified
  3. Unverified → Element refuses to share Megolm keys (default security)
  4. No Megolm keys → bot cannot decrypt inbound messages

This affects any bot deployment needing E2EE: private rooms, multi-user homeservers, compliance environments.

Fix Action

Workaround

Use unencrypted rooms (public_chat preset). Not viable for multi-user homeservers or compliance-required setups.

PR fix notes

PR #66228: fix(matrix): fix E2EE SSSS bootstrap for passwordless token-auth bots

Description (problem / solution / changelog)

Summary

Fixes #66171

Passwordless token-auth Matrix bots fail to complete E2EE bootstrap when the homeserver has existing SSSS data but the bot has no local recovery key.

Problem Statement

Two independent bugs in extensions/matrix/src/matrix/sdk.ts combine to permanently block E2EE bootstrap for passwordless token-auth bots connecting to a homeserver with existing (but inaccessible) SSSS:

Bug 1: MATRIX_INITIAL_CRYPTO_BOOTSTRAP_OPTIONS (line 140) is missing allowSecretStorageRecreateWithoutRecoveryKey: true. Without this flag, when bootstrapCrossSigning encounters a null getSecretStorageKey response (because the bot has no local recovery key), shouldRepairSecretStorage evaluates to false && true = false, so SSSS is never recreated. The explicit bootstrap path (bootstrapOwnDeviceVerification) already sets this flag correctly — the initial auto-startup path does not.

Bug 2: bootstrapCryptoIfNeeded repair path (line ~609) is gated behind this.password?.trim(). Passwordless token-auth bots have no password, so even if Bug 1 were fixed, the repair bootstrap would never run. The intent of the gate was to ensure a UIA credential was available — but UIA failures are already caught and logged gracefully in the existing try/catch, so the gate is overly conservative.

Solution Approach Applied

Two minimal edits to extensions/matrix/src/matrix/sdk.ts:

Edit 1 — Add flag to initial bootstrap options (~line 140):

const MATRIX_INITIAL_CRYPTO_BOOTSTRAP_OPTIONS = {
  allowAutomaticCrossSigningReset: false,
  allowSecretStorageRecreateWithoutRecoveryKey: true,  // added
} satisfies MatrixCryptoBootstrapOptions;

Edit 2 — Remove password gate in repair path (~line 609): Replace else if (this.password?.trim()) { ... } else { LogService.warn(...) } with a plain else { ... } — the try/catch body stays identical, only the gate is removed. Added comment explaining passwordless repair intent to prevent regression.

Test updates in extensions/matrix/src/matrix/sdk.test.ts:

  • Line 1283: Update initial bootstrap options assertion to include new flag
  • Lines 1287-1324: Update test to assert repair runs without password (was asserting repair does NOT run)
  • Lines 1326-1358: New regression test verifying repair catches UIA failure without throwing

Bottleneck Solved

Before: Fresh bot / bot with wiped data directory connecting to homeserver that has existing SSSS → getSecretStorageKey returns null → error silently swallowed → no repair attempted → bot stays unverified forever.

After: Same scenario → getSecretStorageKey returns null → repair bootstrap runs → SSSS recreated with new keys → bot becomes verified.

Expected Outcomes

  • Passwordless token-auth bots can complete E2EE bootstrap on first connection to homeserver with existing SSSS
  • Bots with wiped data directories can recover by recreating SSSS
  • UIA failures (when homeserver requires password but bot has none) are caught and logged as warnings, not fatal errors
  • No behavior change for bots with passwords or explicit bootstrap flows

Current Flow

  1. Bot connects to homeserver with encryption enabled
  2. Initial bootstrap runs with MATRIX_INITIAL_CRYPTO_BOOTSTRAP_OPTIONS (now includes allowSecretStorageRecreateWithoutRecoveryKey: true)
  3. If getSecretStorageKey returns null, bootstrapCrossSigning recreates SSSS
  4. If initial bootstrap incomplete and device not owner-signed, repair bootstrap runs (no password gate)
  5. Repair bootstrap attempts SSSS recreation with MATRIX_AUTOMATIC_REPAIR_BOOTSTRAP_OPTIONS
  6. UIA failures caught and logged, bot continues operating

Verification

pnpm build passes (TypeScript compilation confirms types are correct).

Full test suite not run in this PR (monorepo tests take 10+ min). CI will verify.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • docs/channels/matrix.md (modified, +2/-1)
  • extensions/matrix/src/matrix/sdk.test.ts (modified, +53/-7)
  • extensions/matrix/src/matrix/sdk.ts (modified, +3/-6)
  • extensions/matrix/src/matrix/sdk/crypto-bootstrap.test.ts (modified, +43/-0)
  • extensions/matrix/src/matrix/sdk/crypto-bootstrap.ts (modified, +12/-5)
RAW_BUFFERClick to expand / collapse

Summary

Bot accounts using Matrix E2EE cannot decrypt inbound messages because the getSecretStorageKey callback is not implemented. Cross-signing bootstrap always fails, leaving the bot device permanently unverified.

Environment

  • OpenClaw: 2026.4.12
  • Matrix SDK: @vector-im/matrix-bot-sdk (bundled)
  • Synapse: 1.149.1
  • Node: v22.22.2

Steps to Reproduce

  1. Configure Matrix channel with encryption: true
  2. Start gateway — bot logs into Matrix with a device
  3. Run openclaw matrix verify bootstrap --force-reset-cross-signing
  4. Observe failure: getSecretStorageKey callback returned falsey

Expected Behavior

Cross-signing bootstrap should succeed. The bot device should be able to create or unlock Server-Side Secret Storage (SSSS), publish cross-signing keys, and be marked as verified so other clients share Megolm session keys.

Actual Behavior

getSecretStorageKey() returns null/undefined. Bootstrap fails silently. The bot device cannot publish cross-signing keys, is seen as "unverified" by Element and other clients, does not receive Megolm session keys, and therefore can send encrypted messages but cannot decrypt inbound messages.

Root Cause

The getSecretStorageKey callback is required by matrix-js-sdk to access or create SSSS (Server-Side Secret Storage), which stores master/self-signing/user-signing keys. Without it:

  1. No SSSS → no cross-signing keys published
  2. No cross-signing → Element marks device as unverified
  3. Unverified → Element refuses to share Megolm keys (default security)
  4. No Megolm keys → bot cannot decrypt inbound messages

This affects any bot deployment needing E2EE: private rooms, multi-user homeservers, compliance environments.

Suggested Fix

Implement getSecretStorageKey — either:

  • Accept a recoveryKey or ssssPassword in channel config
  • Auto-generate and persist a recovery key in the bot data directory
  • Derive the SSSS key from the existing password field in Matrix config

Workaround

Use unencrypted rooms (public_chat preset). Not viable for multi-user homeservers or compliance-required setups.

Related

  • #66042 (crypto store deviceId mismatch — same root cause family)
  • #54107 (crypto-node ESM __dirname shim)
  • #7788 (authenticated media endpoints — closed not_planned)

extent analysis

TL;DR

Implement the getSecretStorageKey callback to enable Server-Side Secret Storage (SSSS) and cross-signing, allowing the bot to decrypt inbound messages.

Guidance

  • Implement getSecretStorageKey by either accepting a recoveryKey or ssssPassword in the channel config, auto-generating and persisting a recovery key, or deriving the SSSS key from the existing password field.
  • Verify the implementation by checking if the bot device is marked as verified and can receive Megolm session keys.
  • Test the fix by sending encrypted messages to the bot and verifying that it can decrypt them.
  • Consider the security implications of storing or generating recovery keys and ensure they are handled properly.

Example

// Example implementation of getSecretStorageKey
const getSecretStorageKey = async () => {
  // Either accept a recoveryKey or ssssPassword in channel config
  const recoveryKey = await getRecoveryKeyFromConfig();
  // Or auto-generate and persist a recovery key
  const generatedKey = await generateAndPersistRecoveryKey();
  // Or derive the SSSS key from the existing password field
  const derivedKey = await deriveSSSSKeyFromPassword();
  return recoveryKey || generatedKey || derivedKey;
};

Notes

The provided fix assumes that implementing getSecretStorageKey will resolve the issue. However, the actual implementation details may vary depending on the specific requirements and security considerations of the bot deployment.

Recommendation

Apply the suggested fix by implementing getSecretStorageKey to enable SSSS and cross-signing, as this is the most direct solution to the problem.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING