Problem
Web/PWA build stores the full Stellar secret key (S...) in plaintext localStorage under key stellar_keypair.
Root Cause
micopay/frontend/src/services/secureStorage.ts selects storage backend at runtime:
- Native (Capacitor):
@aparajita/capacitor-secure-storage → Android Keystore (encrypted)
- Web/PWA: custom
webStore wrapper → window.localStorage.setItem('stellar_keypair', JSON.stringify({ publicKey, secretKey })) PLAINTEXT
Impact
| Vector |
Risk |
| XSS |
Any XSS in the SPA → localStorage.stellar_keypair → full wallet control |
| Malicious extension |
Browser extensions with host permissions read all localStorage |
| DevTools / debugging |
Secret visible in Application tab, crash reports, HAR files |
| Shared device |
Anyone with browser access extracts the seed |
Severity: HIGH — Single XSS = total account compromise (all funds).
Evidence
// micopay/frontend/src/services/secureStorage.ts:13-23
const webStore: KvStore = {
async get(key: string) {
const v = localStorage.getItem(key);
return v ? JSON.parse(v) : null;
},
async set(key: string, value: unknown) {
localStorage.setItem(key, JSON.stringify(value)); // ← secretKey stored in plaintext
},
// ...
};
// micopay/frontend/src/services/secureStorage.ts:27-30
async function getStore(): Promise<KvStore> {
if (!Capacitor.isNativePlatform()) return webStore; // ← Web/PWA gets plaintext store
// ...
}
Solution Options
| Option |
Approach |
Effort |
Security |
| A |
WebCrypto SubtleCrypto.encrypt() with key derived from user passphrase (PBKDF2) |
Medium |
🟢 Encrypted at rest |
| B |
WebCrypto generateKey({ extractable: false }) — non-extractable key in CryptoKey object, only usable via sign()/unwrapKey() |
Medium |
🟢 Key never leaves browser crypto subsystem |
| C |
indexedDB + CryptoKey storage (same as B, persistent) |
Medium |
🟢 Persistent, non-extractable |
| D |
Deprecate web secret storage — require native app for custodial features |
Low |
🟢 Eliminates web risk |
Recommended: Option B — Non-extractable CryptoKey for signing operations, secret never in JS memory as string.
Acceptance Criteria
Files to Modify
micopay/frontend/src/services/secureStorage.ts (new webCryptoStore)
micopay/frontend/src/lib/keystore.ts (use crypto store for signing)
micopay/frontend/src/pages/Profile.tsx (remove clipboard export, add secure backup)
- New test:
micopay/frontend/src/services/secureStorage.test.ts
References
- SEC-05 security report (full analysis)
- SEC-22 localstorage secure storage (related)
- SEC-25 secret key clipboard (related — web clipboard also affected)
Labels
security, complexity: high, GrantFox OSS, frontend, web, pwa, crypto, stellar
Problem
Web/PWA build stores the full Stellar secret key (
S...) in plaintextlocalStorageunder keystellar_keypair.Root Cause
micopay/frontend/src/services/secureStorage.tsselects storage backend at runtime:@aparajita/capacitor-secure-storage→ Android Keystore (encrypted)webStorewrapper →window.localStorage.setItem('stellar_keypair', JSON.stringify({ publicKey, secretKey }))PLAINTEXTImpact
localStorage.stellar_keypair→ full wallet controllocalStorageSeverity: HIGH — Single XSS = total account compromise (all funds).
Evidence
Solution Options
SubtleCrypto.encrypt()with key derived from user passphrase (PBKDF2)generateKey({ extractable: false })— non-extractable key inCryptoKeyobject, only usable viasign()/unwrapKey()indexedDB+CryptoKeystorage (same as B, persistent)Recommended: Option B — Non-extractable
CryptoKeyfor signing operations, secret never in JS memory as string.Acceptance Criteria
secretKeynever written tolocalStorage/indexedDB/ any persistent storage in plaintextSubtleCryptonon-extractable key for all signing operationslocalStorage.stellar_keypairdetected → re-encrypted or purged on next loadFiles to Modify
micopay/frontend/src/services/secureStorage.ts(newwebCryptoStore)micopay/frontend/src/lib/keystore.ts(use crypto store for signing)micopay/frontend/src/pages/Profile.tsx(remove clipboard export, add secure backup)micopay/frontend/src/services/secureStorage.test.tsReferences
Labels
security,complexity: high,GrantFox OSS,frontend,web,pwa,crypto,stellar