PR #282 Submitted: Fixing Redux DevTools Private Key Exposure in Steemit Wallet
Follow-up to Issue #275: Redux DevTools Exposure of Private Keys in Steemit Wallet (Next.js)
Quick Update
I'm pleased to announce that PR #282 has been submitted to address the credential exposure vulnerability detailed in Issue #275. This PR implements a minimal, targeted fix that sanitizes sensitive authentication fields before they reach Redux DevTools—preserving developer experience while enforcing secure credential handling.
🔗 PR: steemit/wallet#282
🔗 Original Issue: Issue #275 on Steemit
What Was Addressed
✅ Redux DevTools Credential Masking
Private key fields stored in the Redux auth slice are now redacted before serialization to DevTools:
| Field | Before | After |
|---|---|---|
auth.ownerKey | Visible in plain text | '[REDACTED]' |
auth.activeKey | Visible in plain text | '[REDACTED]' |
auth.postingKey | Visible in plain text | '[REDACTED]' |
auth.memoKey | Visible in plain text | '[REDACTED]' |
auth.privateKey | Visible in plain text | '[REDACTED]' |
✅ Dual-Layer Sanitization
stateSanitizer: Masks key fields in every state snapshot sent to DevToolsactionSanitizer: Redacts payloads forauth/setCredentials, preventing keys from appearing in action logs or time-travel debugging
✅ Serializable Check Correction
The serializableCheck middleware configuration has been updated to:
- Reference the correct action:
auth/setCredentials(previously misreferenced asauth/setPrivateKey) - Ignore all five key fields via a shared
AUTH_KEY_FIELDSconstant, ensuring consistent protection across middleware and sanitizers
const AUTH_KEY_FIELDS = [
'auth.ownerKey',
'auth.activeKey',
'auth.postingKey',
'auth.memoKey',
'auth.privateKey'
] as const;
✅ Production Hardening
devTools: process.env.NODE_ENV === 'production' ? false : { ... }
Redux DevTools remains explicitly disabled in production builds—no extension can inspect the store in a live user session.
Implementation Scope
File Modified: src/lib/store/index.ts (self-contained change)
Breaking Changes: None — runtime behavior is unchanged; sanitizers operate only at the DevTools boundary
Type Safety: Fully preserved — sanitizers are type-aware and do not affect Redux store typings
Core Logic:
// State sanitization for DevTools
const stateSanitizer = (state: RootState) => {
if (!state.auth) return state;
return {
...state,
auth: {
...state.auth,
...Object.fromEntries(
AUTH_KEY_FIELDS.map(field => {
const key = field.split('.')[1];
return [key, state.auth[key as keyof AuthState] ? '[REDACTED]' : null];
})
)
}
};
};
// Action sanitization for credential-carrying actions
const actionSanitizer = (action: AnyAction) =>
action.type === 'auth/setCredentials'
? { ...action, payload: { ...action.payload, ...Object.fromEntries(
AUTH_KEY_FIELDS.map(f => [f.split('.')[1], '[REDACTED]'])
)}}
: action;
Validation Checklist
- [x] Local development: DevTools panel shows
[REDACTED]for allauth.*key fields - [x] Login flow:
setCredentialsaction payloads are sanitized in DevTools timeline - [x] Non-sensitive state (
ui,transactions,account.profile) remains fully inspectable - [x] Production build: DevTools extension cannot connect to store (config-enforced)
- [x] TypeScript compilation: No type errors or runtime behavior changes
- [x] Middleware:
serializableCheckcorrectly ignores all key fields and the proper action
Security Impact Summary
| Attack Vector | Risk Before | Risk After |
|---|---|---|
| DevTools state inspection | Medium-High | ✅ None |
| DevTools action log / time-travel | Medium-High | ✅ None |
| Accidental screenshot / screen-share leak | Medium | ✅ Low |
| Malicious browser extension exfiltration | Medium | ✅ Low |
| Production credential exposure | Low (config-dependent) | ✅ None (explicitly disabled) |
Overall Risk Reduction: Development-only credential exposure eliminated; defense-in-depth strengthened for production.
Review & Collaboration
PR #282 is now open for review. I welcome feedback on:
- Sanitizer implementation approach and edge-case coverage
- Potential additions to
AUTH_KEY_FIELDSif new credential fields are introduced - Documentation updates for secure debugging practices in wallet development
If you're reviewing the code, please pay special attention to:
- The sanitization logic in
stateSanitizerandactionSanitizer - The updated
serializableCheckconfiguration - Ensuring no runtime behavior is altered outside of DevTools serialization
Looking Ahead
Pending merge of PR #282, next steps include:
- Documentation: Update
CONTRIBUTING.mdwith guidelines for secure debugging of credential-handling code - Linting: Explore adding a custom ESLint rule to flag accidental
console.logor logging ofAUTH_KEY_FIELDS - Audit Prep: Document this fix as part of security review artifacts for future internal/external audits
Summary
| Aspect | Detail |
|---|---|
| PR | #282 — fix(store): redact auth private keys from Redux DevTools |
| Related Issue | Issue #275 |
| Scope | src/lib/store/index.ts only |
| Breaking Changes | None |
| Dev Experience | DevTools fully functional; sensitive fields masked |
| Security Gain | Eliminates accidental credential exposure in development workflow |
This fix reinforces a foundational principle for wallet development: debugging convenience must never compromise credential hygiene. By sanitizing at the DevTools boundary, we maintain developer productivity while enforcing least-privilege access to sensitive state.
Support Continued Development
If you find this work valuable and want to support secure, open-source development for the STEEM ecosystem, please consider voting for my witness: blaze.apps
🗳️ Vote Here:
Vote for blaze.apps Witness