Skip to content

Security audit fixes: harden key derivation, demote sensitive logs, version-gate protocol changes#908

Closed
DavidGershony wants to merge 1 commit into
mainfrom
security-fixes
Closed

Security audit fixes: harden key derivation, demote sensitive logs, version-gate protocol changes#908
DavidGershony wants to merge 1 commit into
mainfrom
security-fixes

Conversation

@DavidGershony

Copy link
Copy Markdown
Collaborator

Summary

Addresses findings from an internal security audit with a backward-compatible, version-gated approach. V3+ projects use new secure methods; V1/V2 legacy behavior is preserved for reading existing on-chain data.

All 154 shared tests pass. SDK tests have pre-existing Blockcore build errors from main (unrelated, pending PR #905).

Changes by Severity

Critical

  • C1: Demote sensitive data logs (WitScript, tx hex, signatures, keys) from LogInformation to LogDebug across FounderTransactionActions, InvestorTransactionActions, SeederTransactionActions, DerivationOperations
  • C2: Add WordsMemory/PassphraseMemory properties to WalletWords; fix PsbtOperations to use GetOrDeriveExtKey() instead of accessing .Words directly

High

  • H1: Add DeriveProjectIndicesV2() returning (uint Hi, uint Lo) with 62-bit entropy via two-level BIP-32 hardened path; BuildProjectSubPath version-gated for V3+
  • H2: Replace (List<Coin>?, List<Key>) tuple with strongly-typed SigningCoin record in IWalletOperations
  • H4: Use BIP-341 NUMS point (0x50929b74c1a04954...) as unspendable Taproot internal key for V3+ projects
  • H5: Use public key hash (not private key bytes) for Nostr storage path derivation in V3+; zero sensitive byte arrays in finally blocks for legacy V1/V2 path

Medium

  • M1: Zero private key byte arrays in finally blocks across InvestorTransactionActions, SeederTransactionActions, SpendingTransactionBuilder
  • M8: Prepend 1-byte version marker to V3+ OP_RETURN scripts; parser auto-detects version byte and adjusts data start index

Low

  • Remove redundant .Replace("-","").ToLower() in hex encoding (already lowercase)
  • Replace Console.WriteLine with ILogger.LogError in WalletOperations
  • Replace hardcoded 294 dust threshold with ProtocolConstants.DustThresholdSats

Version Gating Strategy

All protocol-breaking changes use ProjectInfo.Version (existing field, currently 1 or 2):

  • V3+: New secure behavior (NUMS internal key, pubkey-hash storage paths, two-level derivation, OP_RETURN version byte)
  • V1/V2: Legacy behavior preserved for backward compatibility with existing on-chain projects

Files Changed (17 files, +388/-178)

Area Files
Protocol FounderTransactionActions, InvestorTransactionActions, SeederTransactionActions, SpendingTransactionBuilder
Scripts TaprootScriptBuilder, ProjectScriptsBuilder
Derivation DerivationOperations, IDerivationOperations
Wallet WalletOperations, IWalletOperations, PsbtOperations, WalletWords
Tests WalletOperationsTest, FounderTransactionActionTest, InvestmentIntegrationsTests, InvestmentOperationsTest, InvestmentOperations (DataBuilder)

…ersion-gate protocol changes

Addresses findings from internal security audit with backward-compatible,
version-gated approach (V3+ uses new secure methods, V1/V2 legacy preserved):

Critical:
- C1: Demote sensitive data logs (WitScript, tx hex, keys) to LogDebug
- C2: Add WordsMemory/PassphraseMemory to WalletWords; fix PsbtOperations
  to use GetOrDeriveExtKey() instead of accessing Words directly

High:
- H1: Add DeriveProjectIndicesV2() with 62-bit entropy (two-level BIP-32 path)
- H2: Replace (List<Coin>?, List<Key>) tuple with SigningCoin record
- H4: Use BIP-341 NUMS point for unspendable internal key (V3+)
- H5: Use public key hash instead of private key bytes for storage paths (V3+);
  zero sensitive byte arrays in finally blocks for legacy path

Medium:
- M1: Zero private key byte arrays in finally blocks across all transaction builders
- M8: Prepend 1-byte version marker to V3+ OP_RETURN scripts; parser detects
  and adjusts data start index accordingly

Low:
- Remove redundant .Replace('-','').ToLower() in hex encoding
- Replace Console.WriteLine with ILogger.LogError in WalletOperations
- Replace hardcoded 294 dust threshold with ProtocolConstants.DustThresholdSats

All 154 shared tests pass. SDK tests have pre-existing Blockcore build errors
from main (unrelated, pending PR #905).
@DavidGershony DavidGershony requested a review from dangershony July 2, 2026 12:38
@DavidGershony

Copy link
Copy Markdown
Collaborator Author

Splitting into individual PRs per finding for easier review. See linked PRs below.

@DavidGershony

Copy link
Copy Markdown
Collaborator Author

This combined PR has been split into 9 individual PRs for easier review:

# Finding PR Description
1 C1 #910 Demote sensitive data logs from Information to Debug
2 C2 #911 Add WordsMemory/PassphraseMemory and use cached ExtKey
3 H1 #912 Two-level BIP-32 derivation with 62-bit entropy (V3+)
4 H2 #913 Replace (List, List) tuple with SigningCoin record
5 H4 #914 BIP-341 NUMS point as unspendable Taproot internal key (V3+)
6 H5 #915 Pubkey hash for storage paths (V3+) and zero sensitive bytes
7 M1 #916 Zero private key byte arrays in finally blocks
8 M8 #917 Prepend version byte to V3+ OP_RETURN scripts
9 L-fixes #918 Replace hardcoded dust threshold with constant, Console to ILogger

All PRs maintain backward compatibility with existing V1/V2 on-chain projects. Protocol-breaking changes (H1, H4, H5, M8) are version-gated to V3+ projects only.

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