Skip to content

feat: replace plaintext key storage with OWS encrypted vault#57

Open
kevarifin14 wants to merge 1 commit intoPolymarket:mainfrom
kevarifin14:feat/ows-integration
Open

feat: replace plaintext key storage with OWS encrypted vault#57
kevarifin14 wants to merge 1 commit intoPolymarket:mainfrom
kevarifin14:feat/ows-integration

Conversation

@kevarifin14
Copy link

@kevarifin14 kevarifin14 commented Mar 24, 2026

Summary

  • Replaces plaintext private key storage in config.json with OWS (Open Wallet Standard) encrypted vault (AES-256-GCM, scrypt KDF)
  • Private keys are never written to disk in the clear
  • Uses published ows-lib = "1.0.0" and ows-core = "1.0.0" Rust crates directly
  • Legacy plaintext keys in existing configs still work as fallback

Changes

File What
Cargo.toml Added ows-lib, ows-core, hex, zeroize dependencies
src/ows.rs New — OWS backend: create wallet, import key, decrypt signing key. 3 tests.
src/config.rs Added ows_id field to Config. save_wallet stores in OWS. resolve_key decrypts from OWS.
src/commands/wallet.rs wallet create generates keys in OWS vault. wallet import imports into OWS.
src/main.rs Registered ows module

Before / After

Before (~/.config/polymarket/config.json):

{
  "private_key": "0xdeadbeef...",
  "chain_id": 137,
  "signature_type": "proxy"
}

After:

{
  "chain_id": 137,
  "signature_type": "proxy",
  "ows_id": "c8ad47a9-296b-4107-be74-9155695739a3"
}

Test plan

  • cargo check passes
  • cargo test — 49/49 tests pass
  • cargo clippy — clean
  • OWS key import + export round-trip verified
  • OWS wallet creation returns valid UUID
  • Export of nonexistent wallet returns error

Note

Medium Risk
Changes key management and config persistence, including automatic migration and runtime decryption for signing; mistakes could lock users out of wallets or break auth flows.

Overview
Migrates wallet key storage from plaintext config.json to an OWS encrypted vault, persisting only an ows_id in config and decrypting keys on-demand via resolve_key.

Updates wallet create/wallet import to create/import keys into OWS, adds startup migration of legacy plaintext configs, and introduces a new ows module (with tests) plus new crypto/OWS-related dependencies in Cargo.toml/Cargo.lock.

Written by Cursor Bugbot for commit 59092d6. This will update automatically on new commits. Configure here.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

if let Some(ref ows_id) = config.ows_id {
let key = crate::ows::export_private_key(ows_id)
.context("Failed to decrypt key from OWS vault")?;
return Ok((Some((*key).clone()), KeySource::ConfigFile));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zeroizing protection defeated by cloning key into plain String

Medium Severity

resolve_key calls export_private_key which returns Zeroizing<String>, but then does (*key).clone() to produce a plain String. This unprotected copy is returned to all callers (auth.rs, wallet.rs) and won't be zeroed when dropped, contradicting the PR's goal that keys are "wiped from memory" after use.

Fix in Cursor Fix in Web

@kevarifin14 kevarifin14 force-pushed the feat/ows-integration branch from 185072f to 74f88bb Compare March 24, 2026 16:45
Private keys are no longer stored in the clear in config.json. All
key material is managed by the Open Wallet Standard (OWS) encrypted
vault (AES-256-GCM, scrypt KDF).

- Add `ows_id` field to Config — immutable UUID referencing OWS wallet
- Add `src/ows.rs` — OWS backend via `ows-lib` crate (3 tests)
- `wallet create` generates keys directly in OWS vault
- `wallet import` imports keys into OWS vault
- `resolve_key` decrypts from OWS vault when `ows_id` is present
- Legacy plaintext `private_key` field still read as fallback
@kevarifin14 kevarifin14 force-pushed the feat/ows-integration branch from 74f88bb to 59092d6 Compare March 24, 2026 16:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant