Security
Security considerations and best practices for Range integration
Range is designed with security as a primary concern. Understanding the threat model and following best practices ensures your integration remains secure.
Threat Model
Section titled “Threat Model”What Range Protects Against
Section titled “What Range Protects Against”| Threat | How Range Mitigates |
|---|---|
| Forged authorizations | Ed25519 signature verification against trusted range_signer |
| Replay attacks | Timestamp validation within configurable window_size |
| Signature theft | Pubkey in message must match transaction signer |
| Message tampering | Any modification invalidates the Ed25519 signature |
What You Must Protect
Section titled “What You Must Protect”| Threat | Your Responsibility |
|---|---|
| range_signer key compromise | Secure key storage, rotation procedures |
| Admin key compromise | Secure admin keypair, consider multi-sig |
| Backend compromise | Secure backend infrastructure |
| Compliance bypass | Proper compliance checks before signing |
Security Properties
Section titled “Security Properties”Authenticity
Section titled “Authenticity”Only the holder of the range_signer private key can create valid signatures:
The Ed25519 signature algorithm provides 128-bit security level.
Freshness
Section titled “Freshness”Timestamps prevent reuse of old signatures:
Binding
Section titled “Binding”Signatures cannot be used by different users:
Message: "1704067200_Alice_pubkey" └─────────────────────┘ │ ▼ Must match transaction signerIf Bob tries to use Alice’s signature, verification fails with WrongSigner.
Best Practices
Section titled “Best Practices”1. Secure range_signer Key
Section titled “1. Secure range_signer Key”The range_signer keypair is your most critical secret:
- Never expose the private key in client code
- Store in secure key management (AWS KMS, HashiCorp Vault, etc.)
- Use separate keys for devnet and mainnet
- Implement key rotation procedures
// GOOD: Load from secure secret managerconst privateKey = await secretManager.getSecret('RANGE_SIGNER_KEY');
// BAD: Hardcoded or in environment variableconst privateKey = process.env.RANGE_SIGNER_KEY; // Better than hardcoded, but consider KMS2. Choose Appropriate window_size
Section titled “2. Choose Appropriate window_size”| Environment | Recommended window_size | Rationale |
|---|---|---|
| Production | 30-60 seconds | Balance security and usability |
| Testing | 60-120 seconds | Account for slower test networks |
| High-security | 15-30 seconds | Minimize replay window |
// Production settingsconst windowSize = 60n; // 60 seconds
// Monitor for TimestampOutOfWindow errors and adjust if needed3. Implement Key Rotation
Section titled “3. Implement Key Rotation”Plan for key rotation before you need it:
async function rotateRangeSigner( admin: Keypair, newRangeSigner: PublicKey, connection: Connection) { // 1. Update Settings with new signer const instruction = await buildUpdateSettingsInstruction({ admin: admin.publicKey, rangeSigner: newRangeSigner, });
await sendTransaction(new Transaction().add(instruction));
// 2. Immediately update backend to use new key await updateBackendSignerKey(newRangeSigner);
// 3. Log rotation event console.log(`Rotated range_signer to ${newRangeSigner.toBase58()}`);}4. Protect Admin Key
Section titled “4. Protect Admin Key”The admin key controls Settings configuration:
- Use hardware wallet for admin operations
- Consider multi-sig (Squads, etc.) for production
- Never use admin key for routine operations
// Transfer admin to multi-sig after initial setupawait buildTransferAdminInstruction({ admin: initialAdmin.publicKey, newAdmin: squadsMultisigPda,});5. Validate Before Signing
Section titled “5. Validate Before Signing”Backend should validate all requests before signing:
app.post('/api/verify', async (req, res) => { const { pubkey, action, amount } = req.body;
// 1. Validate pubkey format try { new PublicKey(pubkey); } catch { return res.status(400).json({ error: 'Invalid pubkey' }); }
// 2. Check compliance const isCompliant = await checkCompliance(pubkey); if (!isCompliant) { return res.status(403).json({ error: 'Compliance check failed' }); }
// 3. Check rate limits if (!checkRateLimit(pubkey)) { return res.status(429).json({ error: 'Rate limited' }); }
// 4. Validate action-specific rules if (action === 'withdraw' && amount > MAX_WITHDRAW) { return res.status(400).json({ error: 'Amount exceeds limit' }); }
// Only sign after all checks pass const signature = sign(message, rangeSignerKeypair); // ...});6. Monitor and Alert
Section titled “6. Monitor and Alert”Implement monitoring for security events:
// Monitor for suspicious patternsconst suspiciousPatterns = { highFrequencyRequests: (pubkey: string) => { // Alert if > 100 requests in 1 minute }, multipleFailures: (pubkey: string) => { // Alert if > 10 verification failures }, unusualTimestamps: (timestamp: number) => { // Alert if timestamp is significantly off },};
// Alert on Settings changesprogram.addEventListener('VerificationSuccess', (event) => { // Log all verifications for audit});Common Vulnerabilities
Section titled “Common Vulnerabilities”1. Timestamp Manipulation
Section titled “1. Timestamp Manipulation”Risk: Clock drift between backend and Solana.
Mitigation:
- Use NTP to synchronize server clocks
- Add small buffer to window_size for network latency
- Monitor
TimestampOutOfWindowerror rates
2. Signature Replay Within Window
Section titled “2. Signature Replay Within Window”Risk: Same signature used multiple times within window_size.
Mitigation:
- Keep
window_sizesmall - For high-value operations, use on-chain nonces
- Track used signatures in backend (if needed)
3. Callback Bypass (CPI Programs)
Section titled “3. Callback Bypass (CPI Programs)”Risk: Direct calls to on_verify bypassing Range.
Mitigation:
- Always verify CPI caller is Range program
- Use instruction sysvar to check calling program
// CRITICAL: Always include this checkrequire!( calling_ix.program_id == RANGE_PROGRAM_ID, ErrorCode::CpiOnly);4. Message Format Injection
Section titled “4. Message Format Injection”Risk: Malicious data in extended message fields.
Mitigation:
- Validate all parsed fields on-chain
- Use fixed message format
- Limit field lengths
Incident Response
Section titled “Incident Response”Key Compromise Procedure
Section titled “Key Compromise Procedure”If range_signer is compromised:
- Immediately rotate to new key via
update_settings - Update backend with new signing key
- Audit recent transactions for suspicious activity
- Notify affected users if necessary
Admin Compromise Procedure
Section titled “Admin Compromise Procedure”If admin key is compromised:
- If possible,
transfer_adminto secure backup key - If not possible, contact users to migrate to new Settings
- Audit Settings changes
Security Checklist
Section titled “Security Checklist”Before going to production:
-
range_signerstored in secure key management - Admin key secured (hardware wallet or multi-sig)
-
window_sizeappropriate for use case - Backend validates all requests before signing
- Rate limiting implemented
- Compliance checks in place
- CPI programs verify Range caller
- Monitoring and alerting configured
- Key rotation procedure documented
- Incident response plan in place
See Also
Section titled “See Also”- Settings Account - Managing configuration
- Errors - Understanding error codes
- Rate Limiting - Protecting your backend