Case 04 — SKRED Messenger

One key for
every device.

SKRED is an open-source messenger with end-to-end encryption. Reading its open key-management code, I found a fallback key that was the same on every device. Reported through the BSI CERT-Bund — and the vendor responded the way you hope one does: openly, with real technical substance, and with a prompt fix.

By Abbas Hoseiny· Coordinated via BSI CERT-Bund & CERT/CC· Vendor: SKRED SAS / Twinlife

Not every flaw is a drama, and not every good case needs a spectacular finding. This one is the story of a small, concrete mistake in an open-source messenger — and, above all, of a response that shows how coordinated disclosure is supposed to work.

A single key that fits many identical phones the same key on every device
Fig. 1 — one key for all

SKRED stores sensitive settings encrypted on the device. Normally it creates a per-device key in the phone's secure storage (the Android Keystore). When that failed — a known problem on some older devices — a hard-coded fallback key took over. That fallback was the same on every installation.

Why it existed. The intent was benign: still protect data when the device's Keystore fails. But the fallback was not per-device — it was computed deterministically from two values baked into the code, so it was identical everywhere and reconstructible from the open source.

What it means — stated honestly. This was a fallback path, not the normal encryption route, and it affected locally stored settings, not the contents of everyone's messages. Exploiting it required access to the device itself — not a remote attack. The severity lives in the local, device-bound case. That sober framing is the point: a real but clearly bounded flaw.

The fallback key is locked away and only used to read old data new: fail closed fallback key only reads legacy data
Fig. 2 — how the vendor fixed it

In the current state the fallback key is no longer used to encrypt. If the Keystore fails, the app fails closed instead of carrying on with a known key. The old key remains only to decrypt data that already exists, during migration.

The response

A human replies — and fixes.

After the BSI forwarded the report, the vendor's technical lead replied in person. Not a boilerplate answer, but point by point, with real technical substance. He shared additional architecture documentation, pointed to the open-source code base, and began the corrections right away. Alongside the fallback key, the missing certificate pinning was added too — all traceable in the open repository.

What I take from it

This is how it should go.

Coordinated disclosure doesn't live on spectacular holes; it lives on what happens next. SKRED showed how it should go: openness (open source), reachability (a human answers), engagement rather than defensiveness, and prompt, verifiable fixes. That the apps are open is no accident — it is part of the same posture.

Technical write-up

SKRED Messenger — analysis & remediation

Summary

SKRED Messenger (SKRED SAS / Twinlife, France) is open source on Android and iOS (AGPL). The published app was analysed together with the open source code. This report covers two fixed items: a hard-coded AES fallback key in the key-management layer, and a missing certificate-pinning configuration. Both were reported through coordinated disclosure handled by the BSI CERT-Bund (and CERT/CC, VU#629507) and fixed by the vendor; the state is verifiable in the open sources.

Finding 1 · key management

Deterministic AES fallback key, identical on every device

What happens

The key-management layer (KeyChain) protects locally stored "secured" settings with a key from the Android Keystore. If that key's creation fails (a known problem on some older devices/ROMs), the app previously fell back to a hard-coded key. It was computed deterministically from two byte arrays baked into the code via XOR — making it identical on every installation:

// simplified from the open-source KeyChain implementation
static Key getDefaultSecretKey() {
    int n = Math.min(UUID1.length, UUID2.length);
    byte[] key = new byte[n];
    for (int i = 0; i < n; i++)
        key[i] = (byte) (UUID1[i] ^ UUID2[n - 1 - i]);
    return new SecretKeySpec(key, "AES");   // 128-bit, same on every device
}

Impact

On a device whose Keystore failed, locally stored "secured" settings were protected with a publicly known key. Anyone with local access to such a device could decrypt that data. It is a fallback path (not the normal case) and a local, device-bound access — no remote attack and no exposure of everyone's message contents.

Vendor remediation

The fallback key is no longer used to encrypt. If Keystore creation fails, the app fails closed (error state) instead of encrypting with the known key. The key now only decrypts data that already exists, during migration; support for Android 5.0/5.1 (the main source of the broken Keystore) was dropped. Verified in the open sources.

Finding 2 · network security

Missing certificate pinning

What happens

The app shipped without a network security configuration. A certificate installed on the device — e.g. in managed environments — could have allowed the app's TLS connections to be intercepted.

Vendor remediation

The app ships a network security configuration that trusts only system certificates, disables cleartext traffic, and pins a real pin-set for its own domain. Implemented early in the process and confirmed by me in the published app.

On scoring

Why there are no dramatic severity marks here The fallback key was a fallback path for broken Keystores and required local access to the device; the missing certificate pinning required a foreign certificate installed on the device. Both are real but clearly bounded items — and both are fixed. Instead of an inflated score, the honest framing stands: local, device-bound access, no remote attack.

Coordination & disclosure


Coordinated disclosure via the BSI CERT-Bund and CERT/CC. Vendor remediation traceable in the open sources. For defensive and research purposes.