Coldstar Security Overview
Table of Contents
- Introduction
- Encryption Architecture
- Threat Model
- Security Features
- Attack Vectors & Mitigations
- Best Practices
- Recommendations by Use Case
- Known Limitations
- Security Disclosure
Introduction
Coldstar is an air-gappable, USB-bootable Solana wallet designed with security-first principles. This document provides a comprehensive overview of the security architecture, potential threats, and recommended practices for different use cases.
Key Security Principles:
- Private keys are never stored in plaintext
- Keys exist in memory for ~100 microseconds during signing
- Memory locking prevents keys from being swapped to disk
- Immediate zeroization wipes keys from RAM after use
- Rust implementation provides memory safety and guaranteed cleanup
Encryption Architecture
Encryption Flow
Private Key Generation
↓
[Secure Buffer - Memory Locked]
↓
Password → Argon2id KDF → Encryption Key (32 bytes)
↓ ↓
Random Salt Random Nonce (12 bytes)
(32 bytes)
↓
AES-256-GCM Encryption
↓
Encrypted Container (JSON) → Saved to USB
Decryption & Signing Flow
Encrypted Container (from USB)
↓
Password → Argon2id KDF (same parameters)
↓
Decryption Key
↓
AES-256-GCM Decrypt → [Secure Buffer - Memory Locked]
↓
Sign Transaction (~100 microseconds)
↓
Zeroize Memory (overwrite private key with zeros)
↓
Return Signature Only
Cryptographic Algorithms
| Component | Algorithm | Parameters |
|---|---|---|
| Key Derivation | Argon2id | 64 MB RAM, 3 iterations, 4 parallel threads |
| Encryption | AES-256-GCM | 256-bit key, 96-bit nonce |
| Authentication | GCM | Authenticated encryption (detects tampering) |
| Signing | Ed25519 | Solana-compatible elliptic curve |
| Encoding | Base64 (storage), Base58 (public keys) | Standard encodings |
Storage Format
Encrypted wallet containers are stored as JSON:
{
"version": 1,
"salt": "base64_encoded_32_bytes",
"nonce": "base64_encoded_12_bytes",
"ciphertext": "base64_encoded_encrypted_key",
"public_key": "base58_solana_address"
}
Why This Is Secure
-
Argon2id - Memory-hard KDF prevents GPU-based brute force attacks
-
AES-256-GCM - Provides both encryption and authentication (tamper detection)
-
Memory locking (
mlock) - Prevents private keys from being swapped to disk -
Transient decryption - Keys exist in plaintext for ~100 microseconds only
-
Automatic zeroization - Rust's
Droptrait guarantees memory is wiped even on panic - USB seizure resistant - Encrypted container is useless without password
Threat Model
Compromise Levels & Risk Assessment
| Compromise Level | What This Means | Likelihood | Can Private Keys Be Exposed? | Risk Level |
|---|---|---|---|---|
| No compromise (clean OS) | Fully patched OS, no malware, normal user behaviour | High (70-80%) | No (practically) — Keys exist for ~100μs, immediately wiped | Safe |
| Low-risk user-space malware | Adware, browser extensions, clipboard clippers | Common (15-20%) | Very unlikely — Generic malware not targeting crypto operations | Low Risk (~5%) |
| Active crypto-targeting malware | RATs, stealers (Redline, Raccoon, Vidar), memory scanners | Uncommon (3-5%) | Low to Moderate — Must scan memory continuously to catch 100μs window | Moderate Risk (~30%) |
| Targeted Coldstar-specific malware | Custom tooling monitoring Coldstar/Rust processes | Rare (<1%) | Moderate to High — Attacker knows signing patterns, can hook Rust FFI | High Risk (~70%) |
| Privilege escalation / root access | Admin/root access, debugger attachment capability | Very Rare (<0.5%) | High — Can inspect process memory, bypass mlock | Very High Risk (~90%) |
| Kernel-level compromise | Malicious kernel driver, rootkit, modified OS | Extremely Rare (<0.1%) | Very High — Software protections ineffective | Critical Risk (~99%) |
| Firmware / boot compromise | BIOS/UEFI backdoor, bootloader modification | Vanishingly Rare (<0.01%) | Certain — Entire trust model broken | Total Compromise (100%) |
Typical Attack Causes
- Low-risk malware: Phishing, malicious browser add-ons, bundled software
- Active malware: Pirated software, cracked tools, torrent downloads
- Targeted attacks: High-value targets (whales, exchanges), reconnaissance
- Privilege escalation: Exploited 0-day vulnerabilities, social engineering
- Kernel/Firmware: Nation-state actors, advanced persistent threats (APT)
Security Features
Rust Secure Signer Implementation
File: secure_signer/src/crypto.rs
Key Features:
- SecureBuffer - Custom type with automatic memory wiping on drop
- Memory Locking - Uses
mlock()to prevent swapping to disk - Immediate Zeroization - Private key overwritten with zeros after signing
- Panic Safety - Cleanup guaranteed even on errors (Rust's RAII)
- No Python Exposure - Private keys never enter Python memory space
Code Example:
impl Drop for SecureBuffer {
fn drop(&mut self) {
// Guaranteed to run even on panic
self.zeroize();
unsafe { munlock(self.ptr, self.len); }
}
}
Python Implementation (Fallback)
File: src/secure_memory.py
Features:
- Argon2i KDF - GPU-resistant password hashing
- XSalsa20-Poly1305 - Authenticated encryption (PyNaCl)
- Manual cleanup -
del+gc.collect()(less reliable than Rust)
Note: Python implementation is less secure due to unpredictable garbage collection. Rust version is strongly recommended for production use.
Attack Vectors & Mitigations
1. Memory Capture Attacks
Attack: Malware scans process memory to capture private key during signing.
What Attacker Sees:
Memory Address: 0x7fff5fbff000
Raw Bytes (32-byte Ed25519 seed):
[a3, f2, 1b, 8e, 4d, 7c, 9a, 2f,
b5, 6e, 3d, 8c, 1a, 4f, 7e, 2b, ...]
Duration: ~100 microseconds
Mitigations:
- Minimal exposure window (100μs vs Python's seconds)
- Memory locking prevents swap file exposure
- Immediate zeroization
- Not effective against: Continuous memory scanning malware
- Defense: Use air-gapped signing for high-value transactions
2. Clipboard Hijacking
Attack: Malware replaces copied wallet addresses with attacker's address.
Mitigations:
- Transaction verification display before signing
- Address whitelist system (trusted addresses only)
- Manual confirmation required
- User must verify addresses visually
3. Phishing & Social Engineering
Attack: User tricked into signing malicious transaction or revealing password.
Mitigations:
- Clear transaction details display before signing
- Explicit "CONFIRM" required before decrypting keys
- Amount limits for online signing
- Password strength requirements
4. Cold Boot Attacks
Attack: RAM frozen with liquid nitrogen, contents extracted after power-off.
Mitigations:
- Memory locking makes this harder
- Immediate zeroization reduces window
- Not fully prevented: Keys recoverable for seconds after zeroization
- Defense: Physical security, encrypted RAM (CPU feature)
5. Supply Chain Attacks
Attack: Compromised hardware/software introduced before user receives it.
Mitigations:
- Open-source code (auditable)
- Reproducible builds
- Cannot prevent: Firmware-level backdoors, compromised CPUs
- Defense: Hardware wallets from trusted vendors
Best Practices
For All Users
-
Strong Passwords - Minimum 12 characters - Mix uppercase, lowercase, numbers, symbols - Never reuse passwords - Consider using a password manager
-
Verify Transactions - Always check recipient address matches your intention - Confirm amounts are correct - Never sign transactions you didn't create
-
Keep Software Updated - Update Coldstar regularly - Apply OS security patches - Use latest Rust signer version
-
Physical Security - Store USB wallet in secure location - Use encrypted USB drives - Consider using multiple backups
For Enhanced Security
-
Amount Limits - Keep online wallets under $100 for daily use - Store larger amounts in air-gapped cold storage - Use separate wallets for different risk levels
-
Environment Isolation - Use dedicated VM for signing (no network) - Run from live USB OS (Alpine Linux) - Clear clipboard before/after use
-
Audit & Monitoring - Review transaction history regularly - Monitor for unusual signing patterns - Enable logging for forensic analysis
For Maximum Security (Air-Gapped Signing)
-
Dedicated Offline Computer - Purchase used laptop (~$100-150) - Physically remove WiFi/Bluetooth cards - Never connect to internet, ever - Boot from Coldstar USB only
-
Transaction Workflow
ONLINE COMPUTER Create unsigned transaction USB transfer OFFLINE COMPUTER Sign with Coldstar USB transfer ONLINE COMPUTER Broadcast signed transaction -
Additional Hardening
- Use hardware wallet as second factor
- Implement multi-signature (2-of-3 keys)
- Store backup seeds in bank safe deposit box
Recommendations by Use Case
Daily Transactions (< $500 balance)
Setup: Online Coldstar with standard security
Protections:
- Rust secure signer
- Transaction verification
- Strong password
Risk Level: Low to Moderate Acceptable For: Daily purchases, testing, small trades
Active Trading ($500 - $5,000)
Setup: Online Coldstar with enhanced security
Additional Protections:
- Amount limits (max $50 per transaction online)
- Address whitelist (trusted recipients only)
- Anomaly detection (unusual patterns blocked)
- Fresh password required for large amounts
Risk Level: Low Acceptable For: Regular trading, DeFi interactions
Serious Holdings ($5,000 - $50,000)
Setup: Air-gapped signing mandatory
Required Setup:
- Dedicated offline laptop (never online)
- USB transfer for transactions
- Physical security for hardware
Additional Recommendations:
- Hardware wallet as backup
- Multi-signature wallet (2-of-3)
- Regular security audits
Risk Level: Very Low Acceptable For: Long-term holdings, investment portfolios
High-Value Assets (> $50,000)
Setup: Air-gap + Hardware Wallet + Multi-Sig
Required Setup:
- Air-gapped Coldstar (offline signing)
- Hardware wallet (Ledger/Trezor) as second factor
- Multi-signature (3-of-5 keys across different locations)
- Bank safe deposit box for seed backups
Additional Recommendations:
- Professional security audit
- Insurance coverage
- Legal documentation for estate planning
Risk Level: Minimal Acceptable For: Institution-grade security, large portfolios
Known Limitations
What Coldstar CAN Protect Against
Brute-force password attacks (Argon2id)
File theft without password (AES-256-GCM encryption)
Swap file exposure (memory locking)
Accidental memory leaks (automatic zeroization)
Simple malware (adware, clipboard hijackers)
Forensic analysis of RAM dumps (minimal exposure)
What Coldstar CANNOT Protect Against
Sophisticated memory scanning malware (active user-space)
Kernel-level rootkits (can bypass all protections)
Firmware/BIOS backdoors (below OS level)
Physical access attacks (evil maid, DMA)
User error (phishing, password reuse)
Compromised hardware (supply chain attacks)
Design Trade-offs
Security vs Usability:
- Online signing is convenient but riskier
- Air-gapped signing is secure but requires extra hardware
- Balance depends on amount at risk
Python vs Rust:
- Python implementation easier to audit but less secure
- Rust implementation more complex but provides memory guarantees
- Rust version strongly recommended for production
Security Disclosure
Reporting Vulnerabilities
If you discover a security vulnerability in Coldstar, please report it responsibly:
-
Do NOT open a public GitHub issue
-
Email security details to: syrem.dev@gmail.com
-
Include: - Description of the vulnerability - Steps to reproduce - Potential impact - Suggested fix (if available)
Response Timeline
- 24 hours - Initial acknowledgment
- 3 days - Preliminary assessment
- 7 days - Fix developed and tested
- Coordinated disclosure - Public announcement after patch released
Security Audit Status
Coldstar is open-source and community-audited. Professional security audits are planned for future releases. Contributions and code reviews are welcome.
Conclusion
Coldstar provides strong cryptographic security for Solana private keys through:
- Military-grade encryption (AES-256-GCM + Argon2id)
- Minimal memory exposure (~100 microseconds)
- Memory safety guarantees (Rust)
- Air-gap capability (offline signing)
The security of your wallet ultimately depends on:
-
Your threat model (how much are you protecting?)
-
Your operational security (passwords, physical security)
-
Your execution environment (clean OS vs compromised)
Choose the appropriate security level for your use case and always assume that convenience is the enemy of security.
For maximum protection: Air-gap everything.
Security Audit Findings
Audit Date: February 23, 2026
Auditor: Automated Security Review
Scope: Full codebase including Rust signer, Python application, and dependencies
Overview
A comprehensive security audit was conducted on the Coldstar cold wallet system. The audit examined:
- Rust secure signer implementation (
secure_signer/) - Python wallet management and transaction handling
- USB device management and filesystem operations
- Network RPC communication
- Cryptographic implementations
- Dependency vulnerabilities
- Input validation and sanitization
- File permissions and access controls
Critical Findings
No critical vulnerabilities were identified that would allow direct compromise of private keys under normal operating conditions.
High Priority Findings
1. Subprocess Command Execution Without Sanitization
Location: src/iso_builder.py, src/usb.py
Severity: High
Risk: Command injection if untrusted input reaches subprocess calls
Description:
Multiple subprocess calls throughout the codebase execute system commands with user-influenced parameters. While most use subprocess.run() without shell=True (which is secure), device paths and mount points could potentially be manipulated.
Examples:
# src/usb.py - Line ~270+
subprocess.run(['diskutil', 'info', '-plist', device_id], ...)
# src/iso_builder.py - Various locations
subprocess.run(['parted', '-s', str(image_path), 'mklabel', 'msdos'], ...)
subprocess.run(['mount', partition, str(mount_point)], ...)
Impact:
If an attacker can control device identifiers or paths (e.g., through symlinks or specially crafted USB device labels), they might be able to execute arbitrary commands with the privileges of the Python process.
Mitigation:
- Already using
subprocess.run()withoutshell=True(good practice) - Need to add strict validation of all device paths and identifiers
- Should sanitize mount points and verify they're within expected directories
- Consider using absolute paths and checking for symlinks
Recommendation:
import os
import re
def validate_device_path(path: str) -> bool:
"""Validate device path to prevent injection"""
# Only allow /dev/* paths on Unix-like systems
if not path.startswith('/dev/'):
return False
# Prevent path traversal
if '..' in path or '//' in path:
return False
# Only allow expected device name patterns
if not re.match(r'^/dev/(sd[a-z]\d*|disk\d+s?\d*)$', path):
return False
# Resolve symlinks and verify still in /dev
try:
real_path = os.path.realpath(path)
return real_path.startswith('/dev/')
except:
return False
2. Unvalidated Network RPC Input
Location: src/network.py
Severity: High
Risk: RPC endpoint injection or malicious response handling
Description:
The SolanaNetwork class makes RPC calls to Solana endpoints but does not strictly validate responses. A malicious or compromised RPC endpoint could return crafted responses.
Examples:
# src/network.py
def get_balance(self, public_key: str) -> Optional[float]:
result = self._make_rpc_request("getBalance", [public_key])
lamports = result.get("result", {}).get("value", 0) # No validation
return lamports / LAMPORTS_PER_SOL
Impact:
- Incorrect balance display could lead to user errors
- Malicious blockhash could cause transaction failures
- Type confusion if RPC returns unexpected data types
Mitigation:
- Add strict type checking and range validation for all RPC responses
- Implement maximum values for balance and other numeric fields
- Validate blockhash format before use
Recommendation:
def get_balance(self, public_key: str) -> Optional[float]:
result = self._make_rpc_request("getBalance", [public_key])
if "error" in result:
print_error(f"RPC Error: {result['error']['message']}")
return None
try:
lamports = result.get("result", {}).get("value", 0)
# Validate reasonable range
if not isinstance(lamports, (int, float)) or lamports < 0:
print_error("Invalid balance value from RPC")
return None
# Solana's max supply is ~500M SOL
if lamports > 1_000_000_000 * LAMPORTS_PER_SOL:
print_error("Balance exceeds maximum possible value")
return None
return lamports / LAMPORTS_PER_SOL
except (TypeError, ValueError) as e:
print_error(f"Error parsing balance: {e}")
return None
Medium Priority Findings
3. Insufficient Password Strength Enforcement
Location: src/wallet.py - save_keypair() method
Severity: Medium
Risk: Weak passwords may be brute-forced despite Argon2id
Description:
While the system requires non-empty passwords, there is no enforcement of password complexity requirements (minimum length, character diversity, etc.).
Current Code:
if not password:
print_error("Password cannot be empty!")
return False
Impact:
Users may choose weak passwords like "password" or "12345678", which could be cracked despite Argon2id's GPU resistance. Although the parameters are strong (64MB memory, 3 iterations), simple passwords remain vulnerable to dictionary attacks.
Recommendation:
def validate_password_strength(password: str) -> Tuple[bool, str]:
"""Validate password meets security requirements"""
if len(password) < 12:
return False, "Password must be at least 12 characters long"
if not any(c.isupper() for c in password):
return False, "Password must contain at least one uppercase letter"
if not any(c.islower() for c in password):
return False, "Password must contain at least one lowercase letter"
if not any(c.isdigit() for c in password):
return False, "Password must contain at least one number"
# Check against common passwords
common_passwords = {'password', '12345678', 'qwerty', ...}
if password.lower() in common_passwords:
return False, "Password is too common. Please choose a stronger password"
return True, "Password meets requirements"
4. Potential TOCTOU (Time-of-Check-Time-of-Use) Issues
Location: src/wallet.py - File operations
Severity: Medium
Risk: Race condition in file checks and operations
Description:
The code checks if files exist and then operates on them in separate steps, which creates a window for race conditions.
Example:
if not load_path.exists():
print_error(f"Keypair file not found: {load_path}")
return None
with open(load_path, 'r') as f: # File could be deleted/modified here
file_content = f.read()
Impact:
In a multi-process environment or with symbolic link attacks, files could be swapped between the check and use, potentially leading to reading wrong files or denial of service.
Recommendation:
- Use exception handling instead of pre-checks
- Open files directly and handle FileNotFoundError
- Consider using atomic file operations
try:
with open(load_path, 'r') as f:
file_content = f.read()
except FileNotFoundError:
print_error(f"Keypair file not found: {load_path}")
return None
except PermissionError:
print_error(f"Permission denied: {load_path}")
return None
5. Hardcoded Infrastructure Fee Wallet
Location: config.py
Severity: Medium
Risk: Fee wallet could be compromised or misused
Description:
The infrastructure fee wallet address is hardcoded in the configuration:
INFRASTRUCTURE_FEE_WALLET = "Cak1aAwxM2jTdu7AtdaHbqAc3Dfafts7KdsHNrtXN5rT"
Impact:
- If this wallet's private key is compromised, fees go to attacker
- Users cannot verify or change the fee recipient
- No transparency about fee usage
Recommendation:
- Document the fee structure clearly in user-facing documentation
- Consider making fees optional or configurable
- Implement fee wallet rotation mechanism
- Provide transparency reports on fee usage
6. Python Memory Safety Limitations
Location: src/secure_memory.py
Severity: Medium
Risk: Private keys may linger in Python memory despite cleanup attempts
Description:
The Python fallback implementation uses gc.collect() and del to clear sensitive data, but Python's garbage collector does not guarantee immediate cleanup or memory zeroization.
Current Code:
# Clean up sensitive data
del key
del password_bytes
gc.collect()
Impact:
Private keys may remain in memory longer than intended, potentially accessible through memory dumps or during Python's garbage collection cycle.
Mitigation Status:
- Rust signer is now REQUIRED (good!)
- Python implementation is documented as less secure
- System forces use of Rust signer in production
No Action Needed - The codebase already correctly mandates Rust signer usage and exits if not available.
Low Priority Findings
7. Missing Input Validation on Public Key Addresses
Location: Multiple files
Severity: Low
Risk: Malformed addresses could cause crashes or undefined behavior
Description:
While there is a validate_address() method in WalletManager, it's not consistently used before operations. Some functions accept public key strings without validation.
Example:
# src/transaction.py - Line 68
def create_transfer_transaction(self, from_pubkey: str, to_pubkey: str, ...):
from_pk = Pubkey.from_string(from_pubkey) # May raise exception if invalid
Recommendation:
- Always validate public keys before parsing
- Use wrapper function with proper error handling
- Return user-friendly error messages
8. Potential Information Disclosure in Error Messages
Location: Various error handling blocks
Severity: Low
Risk: Verbose error messages might leak system information
Description:
Some error messages include detailed exception information that could reveal system paths or internal structure.
Example:
except Exception as e:
print_error(f"Failed to load keypair: {e}")
import traceback
print_warning(f"Details: {traceback.format_exc()}")
Recommendation:
- In production mode, log detailed errors to a secure file
- Show users simplified error messages
- Implement debug vs. production error handling modes
9. HTTP Client Timeout Configuration
Location: src/network.py
Severity: Low
Risk: Long timeouts could cause application hangs
Description:
HTTP client has a 30-second timeout, which could make the application appear frozen to users.
self.client = httpx.Client(timeout=30.0)
Recommendation:
- Consider reducing timeout for better responsiveness
- Implement retry logic with exponential backoff
- Add user-visible progress indicators for network operations
Positive Security Findings
The following security best practices are correctly implemented:
Rust Secure Signer - Required for all signing operations, provides memory locking and automatic zeroization
Argon2id KDF - Strong parameters (64MB RAM, 3 iterations) resist GPU attacks
AES-256-GCM - Authenticated encryption prevents tampering
No shell=True - All subprocess calls avoid shell interpretation
File Permissions - Wallet files are created with 0o600 (read/write owner only)
Memory Locking - Rust implementation uses mlock() to prevent swapping
Zeroization - Private keys are explicitly overwritten with zeros
Environment Variable Isolation - Permissive mode controlled via environment variable
Panic Safety - Rust Drop trait ensures cleanup even on panic
No Plaintext Storage - All private keys are encrypted at rest
Dependency Security
Python Dependencies (pyproject.toml)
aiofiles>=25.1.0
base58>=2.1.1
httpx>=0.28.1
pynacl>=1.6.1
questionary>=2.1.1
rich>=14.2.0
solana>=0.36.10
solders>=0.27.1
Status: All dependencies are at recent versions. No known critical vulnerabilities identified.
Recommendation: Implement automated dependency scanning with tools like:
pip-auditfor Pythoncargo auditfor Rust- GitHub Dependabot alerts
Rust Dependencies (Cargo.toml)
Key security-critical dependencies:
ed25519-dalek = "2.1"- Current stable version, actively maintainedaes-gcm = "0.10"- Current version of RustCrypto's AES-GCMargon2 = "0.5"- Current version, secure parameterszeroize = "1.7"- Memory zeroization library
Status: All cryptographic dependencies are from RustCrypto project (well-audited, industry standard).
Recommendation: Continue monitoring for updates, especially for cryptographic libraries.
Recommendations Summary
Immediate Actions (High Priority)
- Implement strict device path validation in
usb.py - Add RPC response validation in
network.py - Implement password strength requirements in
wallet.py
Short-term Actions (Medium Priority)
-
Consider fee wallet transparency and documentation
-
Fix TOCTOU issues by using exception-based file handling
-
Add consistent input validation for all public key operations
Long-term Actions (Low Priority)
-
Implement production vs. debug error message modes
-
Add automated dependency vulnerability scanning
-
Create security testing suite with fuzzing
Testing Recommendations
To validate security properties, implement:
-
Unit Tests - Test password validation with weak passwords - Test path validation with malicious inputs - Test RPC response parsing with malformed data
-
Integration Tests - Test entire signing flow with Rust signer - Verify file permissions after wallet creation - Test error handling paths
-
Security Tests - Fuzzing for parser inputs (JSON, base64, base58) - Memory leak detection - Timing attack resistance for decryption
-
Manual Testing - Verify memory zeroization with debugger - Test USB device handling with malformed labels - Test RPC behavior with mock malicious endpoint
Last Updated: February 23, 2026
Security Audit Version: 1.0
Coldstar Project: https://github.com/devsyrem/homebrew-coldstar