From 0d1de6e546e1eebd0cd237704a9780231ba0ad08 Mon Sep 17 00:00:00 2001 From: zhaog100 Date: Thu, 26 Mar 2026 09:53:09 +0800 Subject: [PATCH] security: fix invalid threshold input validation in Shamir secret sharing (#48) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🚨 Security Vulnerability Fix **Severity:** Significant Implementation Bug **Issue:** #48 **Bounty Tier:** 0.05 BTC+ ## Problem When invalid threshold/total values were entered (e.g., '$ of 5', '$ of 8'), the tool: - Silently fell back to trivial 'duplicate + cycle checksum' mode - Generated identical shares with only the 12th word changing - Leaked the checksum-index hiding mechanism - Exposed internal Shamir implementation details **Root Cause:** No type validation for threshold and total parameters. ## Solution Added comprehensive input validation in `__split_secret()`: 1. **Undefined/Null checks** - Rejects missing parameters 2. **Type conversion** - Handles string form inputs 3. **NaN validation** - Rejects non-numeric input ('$', '', etc.) 4. **Integer validation** - Ensures whole numbers only 5. **Range validation** - Enforces 1-255 bounds 6. **Logical validation** - threshold ≤ total ## Changes - Modified `src/functions/shamir_secret_sharing.js` - Added 25+ lines of validation logic - Clear error messages for each failure case ## Impact - ✅ Prevents fallback mode exploitation - ✅ Protects checksum-index hiding mechanism - ✅ Clear user feedback on invalid input - ✅ Maintains backward compatibility for valid inputs ## Testing Valid inputs still work: - threshold=3, total=5 ✅ - threshold=2, total=10 ✅ Invalid inputs now rejected: - threshold='$', total=5 ❌ - threshold='', total=5 ❌ - threshold=NaN, total=5 ❌ - threshold=0, total=5 ❌ - threshold=256, total=5 ❌ Closes #48 Payment: BTC bc1q9ezttyulgmm7lh8a086tsug990h4j3tflk3yc7 --- src/functions/shamir_secret_sharing.js | 36 ++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/functions/shamir_secret_sharing.js b/src/functions/shamir_secret_sharing.js index def4f16..29cc198 100644 --- a/src/functions/shamir_secret_sharing.js +++ b/src/functions/shamir_secret_sharing.js @@ -86,8 +86,40 @@ module.exports = function (S) { S.__split_secret = (threshold, total, secret, indexBits=8) => { - if (threshold > 255) throw new Error("threshold limit 255"); - if (total > 255) throw new Error("total limit 255"); + // SECURITY FIX: Validate threshold and total are valid numbers + // Prevents fallback mode that leaks checksum-index hiding mechanism + if (threshold === undefined || threshold === null) { + throw new Error("threshold must be a number between 1 and 255"); + } + if (total === undefined || total === null) { + throw new Error("total must be a number between 1 and 255"); + } + + // Convert to numbers if strings (form input) + threshold = Number(threshold); + total = Number(total); + + // Check for NaN (invalid input like "$", "", etc.) + if (isNaN(threshold) || isNaN(total)) { + throw new Error("threshold and total must be valid numbers"); + } + + // Check for non-integer values + if (!Number.isInteger(threshold) || !Number.isInteger(total)) { + throw new Error("threshold and total must be integers"); + } + + // Validate ranges + if (threshold < 1 || threshold > 255) { + throw new Error("threshold must be between 1 and 255"); + } + if (total < 1 || total > 255) { + throw new Error("total must be between 1 and 255"); + } + if (threshold > total) { + throw new Error("threshold cannot be greater than total"); + } + let index_mask = 2**indexBits - 1; if (total > index_mask) throw new Error("index bits is to low"); if (threshold > total) throw new Error("invalid threshold");