-
Notifications
You must be signed in to change notification settings - Fork 4
Closed
Labels
Description
Project
term-challenge
Description
The authentication system uses timestamp-based replay protection with a 5-minute window, but does NOT track used signatures. This allows replay attacks where an attacker can reuse a valid signature multiple times within the 5-minute window.
Error Message
No error - replay attacks succeed silently
Same signature accepted multiple times within 5-minute windowDebug Logs
// src/crypto/auth.rs lines 120-125
/// Check if a timestamp is within the acceptable window (5 minutes)
pub fn is_timestamp_valid(timestamp: i64) -> bool {
let now = chrono::Utc::now().timestamp();
let window = 5 * 60; // 5 minutes
(now - timestamp).abs() < window
}
// No tracking of used signatures anywhere in the codebase!
// grep -rn "used_signature\|signature.*used\|nonce.*track" src/ returns 0 matchesSystem Information
- Bounty Version: 0.1.0
- OS: Ubuntu 24.04 LTS
- Rust: 1.75+Screenshots
No response
Steps to Reproduce
- Capture a valid signed request (e.g., via network sniffing or logs):
{
"validator_hotkey": "5Freal...",
"signature": "0xabc123...",
"timestamp": 1705700000,
"count": 5
}- Replay the exact same request multiple times within 5 minutes:
# Attacker replays 100 times in 5 minutes
for i in {1..100}; do
curl -X POST .../claim_jobs -d '{same payload}'
done- All requests succeed because no nonce/replay tracking exists
Expected Behavior
- Each signature should only be usable ONCE
- Server should track used signatures (nonce table)
- Duplicate signatures should be rejected with "Signature already used"
Actual Behavior
- Signatures can be replayed unlimited times within 5-minute window
- No database table tracking used signatures
- No nonce in signature message
Affected endpoints:
claim_jobs- Attacker can steal all jobsheartbeat- Attacker can fake validator statuslog_task- Attacker can replay task resultssubmit- Attacker can replay submissions
Additional Context
Recommended fix:
- Add nonce to signature message:
let message = format!("claim_jobs:{}:{}", timestamp, random_nonce);- Track used signatures in database:
CREATE TABLE used_signatures (
signature_hash TEXT PRIMARY KEY,
used_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);- Check before accepting:
fn is_signature_valid(sig: &str, ...) -> bool {
let sig_hash = sha256(sig);
if db.signature_exists(&sig_hash) {
return false; // Replay attack!
}
db.mark_signature_used(&sig_hash);
true
}Reactions are currently unavailable