Lack of input validations
Description
The code does not properly validate user inputs in several areas:
Numeric values
Index values' range
Length of buffer object
Additionally, required input values can be missing. The stakingTimeLock
is two bytes for staking time, which can overflow when the input exceeds 65535
(approximately 455 days). Although there is a check in validate()
, it is not utilized in the codebase.
buildDataEmbedScript(): Buffer {
// 4 bytes for magic bytes
const magicBytes = Buffer.from("01020304", "hex");
// 1 byte for version
const version = Buffer.alloc(1);
version.writeUInt8(0);
// 2 bytes for staking time
! const stakingTimeLock = Buffer.alloc(2); // here
// [...]
}
That lockTime
is only two bytes also affects the Go implementation of btcstaking
:
func buildTimeLockScript(
pubKey *btcec.PublicKey,
lockTime uint16,
) ([]byte, error) {
builder := txscript.NewScriptBuilder()
builder.AddData(schnorr.SerializePubKey(pubKey))
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
builder.AddInt64(int64(lockTime))
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
return builder.Script()
}
Impact
The lack of input validation can lead to unintended behavior or unexpected interruptions in code execution.
Recommendations
We recommend the following:
Check that numeric values such as the amount, fee, and rates are nonnegative.
Check that index values are within a valid range.
Check and ensure that buffer objects have expected lengths, like checking
pks.length
inutils/stakingScript.ts::buildMultiKeyScript
.Check that the required input values are not missing when creating an instance of the
StakingScriptData
class.Validate the script in the constructor.
Use at least 32 bits for lock time (Assuming 10-minute blocks, there are 144 blocks per day, so blocks would not overflow for approximately 81,715 years).
Remediation
Babylon acknowledged this issue and created a fix in pull request #17↗.