# \[ideation\] Secure Offchain Storage via Session Key Derivation and Zeroization

**URL:** https://ghostforum.org/t/ideation-secure-offchain-storage-via-session-key-derivation-and-zeroization/147
**Category:** Submitted
**Tags:** exodus-pallet
**Created:** [October 5, 2026, 2:25pm UTC](https://ghostforum.org/t/ideation-secure-offchain-storage-via-session-key-derivation-and-zeroization/147 "2026-10-05T14:25:42Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![VoidDragon](https://ghostforum.org/user_avatar/ghostforum.org/voiddragon/32/16_2.png) [@VoidDragon](https://ghostforum.org/u/VoidDragon)
#### Post date: [October 5, 2026, 2:25pm UTC](https://ghostforum.org/t/ideation-secure-offchain-storage-via-session-key-derivation-and-zeroization/147/1 "2026-10-05T14:25:43Z")

</div>

### Context & Overview

During distributed key generation (DKG) and collective signing inside `pallets/exodus`, secret and public packages are stored in the offchain storage of the validator’s node for later use. For public packages, this isn’t important - but for secret ones, it could be potentially dangerous.

Possible leakage vectors:

1. Some validators like to transfer the `db/full` folder from one machine to another for faster sync. During transfer, the packages could be stolen, or worse.
2. There is an RPC call `offchain_localStorage` that gives direct access to the underlying storage. While the values are raw for now, if the port is exposed to the internet because of a misconfiguration - or to an unwanted sub-network (in a complex Kubernetes stack or some other multi-machine setup) - the secrets are visible right away.

#### Push Back

The main pushback here is the fact that if a malicious attacker can get direct access to the filesystem, there’s no remedy anyway — because the `keystore` folder with active session keys will be taken right away, so there’s no need to gather secrets from local storage. That’s why I’m questioning the whole idea: is it really necessary?

### **Solution**

Because we already have `ChaChaPoly1305` encryption in place in this pallet, it looks like a good option to reuse it for secrets in offchain storage. For that, the node would need some _symmetric key_ that persists across OCW runs.

For now, the `exodus` pallet is using `sr25519` as the scheme for the session key, and we are locked into the `RuntimeAppPublic` trait, which isn’t very flexible:

```auto
pub trait RuntimeAppPublic: Sized {
    type Signature: Debug + Eq + PartialEq + Clone + TypeInfo + Codec;
    type ProofOfPossession: Debug + Eq + PartialEq + TypeInfo + Clone;

    const ID: KeyTypeId;

    // Required methods
    fn all() -> Vec<Self>;
    fn generate_pair(seed: Option<Vec<u8>>) -> Self;
    fn sign<M: AsRef<[u8]>>(&self, msg: &M) -> Option<Self::Signature>;
    fn verify<M: AsRef<[u8]>>(
        &self,
        msg: &M,
        signature: &Self::Signature,
    ) -> bool;
    fn generate_proof_of_possession(
        &mut self,
        owner: &[u8],
    ) -> Option<Self::ProofOfPossession>;
    fn verify_proof_of_possession(
        &self,
        owner: &[u8],
        pop: &Self::ProofOfPossession,
    ) -> bool;
    fn to_raw_vec(&self) -> Vec<u8> ⓘ;
}

```

In order to fit the _symmetric_ nature between OCW runs, we recommend changing the session key to `ed25519`, which can be used like this:

```auto
// PSEUDO CODE

const ENCRYPTION_PREFIX = "prefix-"

let message = prefix + authority_id.encode() + dkg_index + authority_index;
let signature = authority_id.sign(&message)?;
let symmetric_key = blake2_256(&signature.encode());

// Use it for ChaCha20Poly1305

```

### Zeroization

Because it’s just good practice overall, it would be great to add zeroization for all secrets and the symmetric key itself. The recommendation is to use the [zeroize](https://docs.rs/zeroize/latest/zeroize/) crate - the same one already used as a dependency of the `frost-core` crate.

### **The Question**

In any case, decryption and encryption will require more computation for each OCW. At the same time, leakage of the `keystore` will lead to decryption of the secrets too. In my opinion, the `offchain_localStorage` call and misconfiguration of the ports are the only real use cases.

A review of the proposal is welcome - if you have any thoughts, put them below.
