Skip to content

Commit 6539e3c

Browse files
committed
Add input validation for fee rates, addresses, connections, and contract sizes
1 parent ea9f60a commit 6539e3c

2 files changed

Lines changed: 69 additions & 4 deletions

File tree

ddk-node/src/command.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ pub async fn cli_command(
142142
amount,
143143
fee_rate,
144144
} => {
145+
if fee_rate > 1000 {
146+
return Err(anyhow!(
147+
"Fee rate too high: {} sat/vbyte (max: 1000)",
148+
fee_rate
149+
));
150+
}
145151
let txid = client
146152
.send(SendRequest {
147153
address,
@@ -237,7 +243,12 @@ pub async fn cli_command(
237243
print!("{peers}");
238244
}
239245
CliCommand::Connect { connect_string } => {
240-
let parts = connect_string.split("@").collect::<Vec<&str>>();
246+
let parts: Vec<&str> = connect_string.split('@').collect();
247+
if parts.len() != 2 {
248+
return Err(anyhow!(
249+
"Invalid connection string format. Expected: pubkey@host:port"
250+
));
251+
}
241252
client
242253
.connect_peer(ConnectRequest {
243254
pubkey: parts[0].to_string(),
@@ -330,6 +341,12 @@ async fn interactive_contract_input(
330341
.prompt()?
331342
.parse()?;
332343
let fee_rate: u64 = Text::new("Fee rate (sats/vbyte):").prompt()?.parse()?;
344+
if fee_rate > 1000 {
345+
return Err(anyhow!(
346+
"Fee rate too high: {} sat/vbyte (max: 1000)",
347+
fee_rate
348+
));
349+
}
333350
let min_price: u64 = Text::new("Minimum Bitcoin price:").prompt()?.parse()?;
334351
let max_price: u64 = Text::new("Maximum Bitcoin price:").prompt()?.parse()?;
335352
let num_steps: u64 = Text::new("Number of rounding steps:").prompt()?.parse()?;
@@ -372,6 +389,12 @@ async fn interactive_contract_input(
372389
outcome_payouts.push(outcome_payout);
373390
}
374391
let fee_rate: u64 = Text::new("Fee rate (sats/vbyte):").prompt()?.parse()?;
392+
if fee_rate > 1000 {
393+
return Err(anyhow!(
394+
"Fee rate too high: {} sat/vbyte (max: 1000)",
395+
fee_rate
396+
));
397+
}
375398
// TODO: list possible events.
376399
ddk_payouts::enumeration::create_contract_input(
377400
outcome_payouts,

ddk-node/src/lib.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,31 @@ impl DdkRpc for DdkNode {
143143
contract_input,
144144
counter_party,
145145
} = request.into_inner();
146+
147+
if contract_input.len() > 1_000_000 {
148+
return Err(Status::new(
149+
Code::InvalidArgument,
150+
"Contract input too large (max: 1MB)",
151+
));
152+
}
153+
146154
let contract_input: ContractInput =
147-
serde_json::from_slice(&contract_input).expect("couldn't get bytes correct");
155+
serde_json::from_slice(&contract_input).map_err(|e| {
156+
Status::new(
157+
Code::InvalidArgument,
158+
format!("Invalid contract input: {}", e),
159+
)
160+
})?;
161+
162+
if contract_input.fee_rate > 1000 {
163+
return Err(Status::new(
164+
Code::InvalidArgument,
165+
format!(
166+
"Fee rate too high: {} sat/vbyte (max: 1000)",
167+
contract_input.fee_rate
168+
),
169+
));
170+
}
148171
let mut oracle_announcements = Vec::new();
149172
for info in &contract_input.contract_infos {
150173
let announcement = self
@@ -297,7 +320,16 @@ impl DdkRpc for DdkNode {
297320
request: Request<ConnectRequest>,
298321
) -> Result<Response<ConnectResponse>, Status> {
299322
let ConnectRequest { pubkey, host } = request.into_inner();
300-
let pubkey = PublicKey::from_str(&pubkey).unwrap();
323+
324+
if host.len() > 255 {
325+
return Err(Status::new(
326+
Code::InvalidArgument,
327+
"Host string too long (max: 255 characters)",
328+
));
329+
}
330+
331+
let pubkey = PublicKey::from_str(&pubkey)
332+
.map_err(|e| Status::new(Code::InvalidArgument, format!("Invalid pubkey: {}", e)))?;
301333
self.node.transport.connect_outbound(pubkey, &host).await;
302334
Ok(Response::new(ConnectResponse {}))
303335
}
@@ -336,7 +368,17 @@ impl DdkRpc for DdkNode {
336368
amount,
337369
fee_rate,
338370
} = request.into_inner();
339-
let address = Address::from_str(&address).unwrap().assume_checked();
371+
372+
if fee_rate > 1000 {
373+
return Err(Status::new(
374+
Code::InvalidArgument,
375+
format!("Fee rate too high: {} sat/vbyte (max: 1000)", fee_rate),
376+
));
377+
}
378+
379+
let address = Address::from_str(&address)
380+
.map_err(|e| Status::new(Code::InvalidArgument, format!("Invalid address: {}", e)))?
381+
.assume_checked();
340382
let amount = Amount::from_sat(amount);
341383
let fee_rate = match FeeRate::from_sat_per_vb(fee_rate) {
342384
Some(f) => f,

0 commit comments

Comments
 (0)