Skip to content

Security: Add input validation and memory clearing for sensitive data#22

Merged
LucienSong merged 1 commit into
mainfrom
security/sdk-input-rpc-validation
May 26, 2026
Merged

Security: Add input validation and memory clearing for sensitive data#22
LucienSong merged 1 commit into
mainfrom
security/sdk-input-rpc-validation

Conversation

@LucienSong
Copy link
Copy Markdown
Collaborator

Summary

This PR addresses three P2 (medium priority) security findings:

SDK-KEYSTORE-001: Keystore password not cleared from memory

Issue: When decrypting a keystore, the password buffer is not zeroed after use, leaving it in memory.
Fix: Password is now converted to Uint8Array and explicitly filled with zeros in a finally block.
Impact: Prevents accidental exposure of sensitive password data in memory dumps.

SDK-INPUT-001: User input validation for addresses and amounts

Issue: SDK may not validate transaction inputs (addresses, amounts, nonces) before signing.
Fix: Added comprehensive input validation layer:

  • Addresses: validates 0x + 64 hex chars (32 bytes) or null
  • Amounts: ensures non-negative bigints
  • Nonces: ensures non-negative integers
  • Gas parameters: ensures non-negative integers
    Impact: Prevents invalid transactions from being constructed.

SDK-RPC-001: RPC URL validation

Issue: SDK client doesn't validate RPC URLs before sending requests.
Fix: Added RPC URL validation:

  • Protocol check: https/wss for remote, http/ws allowed for localhost only
  • IP range check: rejects private IPs (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8)
    Impact: Prevents accidental connections to unintended or internal network endpoints.

Changes

  • Created new validation.ts module with reusable validators
  • Updated buildTransaction() to validate all inputs before constructing
  • Updated provider creation functions to validate RPC URLs
  • Exported validation functions in public API

Testing

  • ✅ All existing tests pass (51 tests)
  • ✅ Build succeeds
  • ✅ No breaking API changes (validation is additive)

- SDK-KEYSTORE-001: Clear password buffer from memory after decryption
  * Convert password string to Uint8Array and fill with zeros in finally block
  * Ensures sensitive password data is not retained in memory

- SDK-INPUT-001: Add comprehensive input validation for transaction inputs
  * Validate addresses: must be valid Shell addresses (0x + 64 hex chars) or null
  * Validate amounts: must be non-negative bigints
  * Validate nonces: must be non-negative integers
  * Validate gas parameters: must be non-negative integers
  * Added validateAddress, validateNonNegativeBigInt, validateNonNegativeInteger functions

- SDK-RPC-001: Add RPC URL validation
  * Validate protocol: https/wss for remote, http/ws allowed for localhost only
  * Reject private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8)
  * Validate in createShellPublicClient, createShellWsClient, createShellProvider
  * Added validateRpcUrl function

All validations are exported in the public API via validation module.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 26, 2026 15:43
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a reusable validation layer to the Shell SDK and wires it into transaction building, provider/client creation, and keystore decryption to address medium-priority security findings around input validation, RPC URL safety checks, and sensitive data handling.

Changes:

  • Introduces src/validation.ts with validators for addresses, non-negative numbers/bigints, and RPC URLs (protocol + private IPv4 range checks).
  • Validates transaction inputs in buildTransaction() before constructing the wire-format request.
  • Validates RPC URLs in provider/client factory functions and exports validators via the root public API.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/validation.ts Adds new validation utilities for tx fields and RPC URLs.
src/transactions.ts Calls validators in buildTransaction() to reject invalid tx inputs early.
src/provider.ts Validates RPC URLs before creating HTTP/WS clients/providers.
src/keystore.ts Attempts to clear password material and ensures derived key / secret key are zeroed.
src/index.ts Exposes validation helpers through the root SDK export.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/validation.ts
Comment on lines +71 to +74
const protocol = url.protocol;
const hostname = url.hostname;
const isLocal = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";

Comment thread src/validation.ts
Comment on lines +31 to +35
export function validateNonNegativeInteger(value: number, fieldName: string): void {
if (!Number.isInteger(value) || value < 0) {
throw new Error(`${fieldName} must be a non-negative integer, got ${value}`);
}
}
Comment thread src/validation.ts
Comment on lines +55 to +59
* Rules:
* - Must be https:// (or http:// for localhost only)
* - Cannot point to private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8)
* - WebSocket URLs must start with wss:// (or ws:// for localhost only)
*
Comment thread src/keystore.ts
Comment on lines +183 to +190
// Convert password to Uint8Array for secure erasure
const passwordBytes = new TextEncoder().encode(password);

try {
const chacha = xchacha20poly1305(derivedKey, nonce);
// Plaintext is sk-only; public key comes from the JSON `public_key` field.
const secretKey = chacha.decrypt(ciphertext);
const derivedKeyHex = await argon2id({
password,
salt,
iterations: ek.kdf_params.t_cost,
Comment thread src/validation.ts
Comment on lines +18 to +22
export function validateNonNegativeBigInt(value: bigint, fieldName: string): void {
if (typeof value !== "bigint" || value < 0n) {
throw new Error(`${fieldName} must be a non-negative bigint, got ${value}`);
}
}
@LucienSong LucienSong merged commit 436fcfd into main May 26, 2026
2 checks passed
@LucienSong LucienSong deleted the security/sdk-input-rpc-validation branch May 26, 2026 15:56
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.

2 participants