Summary
validateAuth() in src/index.ts validates that a signature field exists and has reasonable base64 length, but never actually verifies the signature against the message and claimed address. This means any attacker can send an arbitrary base64 string and pass all auth checks.
Location
src/index.ts, lines ~25-48 (the validateAuth function)
The Problem
The current flow:
- Check that
btc_address, signature, and timestamp exist
- Check timestamp is within 300 seconds
- Check signature looks like base64 (length check)
- Return
{ valid: true }
What's missing: recovering the signer from the signature and verifying it matches btc_address. Without this, the signature field is decorative -- any string that passes the length check is accepted.
Impact
- Any address can impersonate any other address (create tasks, place bids, accept bids, verify work)
- Reputation system is meaningless since actions aren't tied to proven identities
- Payment verification can be spoofed
Suggested Fix
Implement actual BIP-322 signature verification. For a Cloudflare Worker, options include:
- Use
@noble/secp256k1 (pure JS, CF-compatible) to recover the public key from the signature and derive the address
- Or call an external verification endpoint (e.g., the AIBTC MCP server's
btc_verify_message)
The verification should:
- Reconstruct the expected message string (same format used for signing)
- Recover the public key from the signature
- Derive the Bitcoin address from the recovered key
- Compare against the claimed
btc_address
Additional Notes
- The 300-second timestamp window also enables replay attacks within that window. Consider adding a nonce or request ID to prevent replays.
- The
verifyPaymentOnChain() function has a related issue: it checks tx_status === 'success' but doesn't verify the sender is the expected payer.
Found during routine code review.
Summary
validateAuth()insrc/index.tsvalidates that a signature field exists and has reasonable base64 length, but never actually verifies the signature against the message and claimed address. This means any attacker can send an arbitrary base64 string and pass all auth checks.Location
src/index.ts, lines ~25-48 (thevalidateAuthfunction)The Problem
The current flow:
btc_address,signature, andtimestampexist{ valid: true }What's missing: recovering the signer from the signature and verifying it matches
btc_address. Without this, the signature field is decorative -- any string that passes the length check is accepted.Impact
Suggested Fix
Implement actual BIP-322 signature verification. For a Cloudflare Worker, options include:
@noble/secp256k1(pure JS, CF-compatible) to recover the public key from the signature and derive the addressbtc_verify_message)The verification should:
btc_addressAdditional Notes
verifyPaymentOnChain()function has a related issue: it checkstx_status === 'success'but doesn't verify the sender is the expected payer.Found during routine code review.