Please DO NOT open public issues for security vulnerabilities.
If you discover a security vulnerability in Klever Connect SDK, please report it responsibly:
- Email: security@klever.io
- Subject: [SECURITY] Klever Connect SDK - Brief description
- Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We will acknowledge your email within 48 hours and provide a detailed response within 7 days.
| Version | Supported |
|---|---|
| 1.x.x | ✅ |
| < 1.0 | ❌ |
// NEVER hardcode private keys
const PRIVATE_KEY = 'abc123...' // DANGEROUS!
// NEVER store keys in version control
const wallet = new Wallet('hardcoded-key') // INSECURE!
// NEVER store keys in localStorage/sessionStorage (browser)
localStorage.setItem('privateKey', key) // VULNERABLE TO XSS!
// NEVER log private keys
console.log('Private key:', privateKey) // EXPOSES SECRETS!
// NEVER commit .env files with keys
// ❌ .env file in git repository
// NEVER pass keys in URLs
fetch(`https://api.example.com?key=${privateKey}`) // INSECURE!Node.js / Server Applications:
import { PrivateKeyImpl } from '@klever/connect-crypto'
import { NodeWallet } from '@klever/connect-wallet'
// Use environment variables
const privateKey = PrivateKeyImpl.fromHex(process.env.PRIVATE_KEY!)
const wallet = new NodeWallet(privateKey)
// Or load from encrypted PEM file
import { loadPrivateKeyFromPemFile } from '@klever/connect-crypto'
const privateKey2 = loadPrivateKeyFromPemFile('./wallet.pem', process.env.PEM_PASSWORD)Browser / Frontend Applications:
import { BrowserWallet } from '@klever/connect-wallet'
// Use browser extension (RECOMMENDED)
const wallet = await BrowserWallet.connect()
// For temporary operations, generate keys in-memory
import { generateKeyPair } from '@klever/connect-crypto'
const keyPair = await generateKeyPair()
// Use immediately, don't persistReact Native / Mobile Applications:
import * as SecureStore from 'expo-secure-store'
import { PrivateKeyImpl } from '@klever/connect-crypto'
// Store encrypted in secure storage
async function saveKey(privateKey: PrivateKey) {
const hex = privateKey.toHex()
await SecureStore.setItemAsync('wallet_key', hex)
}
// Load from secure storage
async function loadKey(): Promise<PrivateKey> {
const hex = await SecureStore.getItemAsync('wallet_key')
if (!hex) throw new Error('No key found')
return PrivateKeyImpl.fromHex(hex)
}✅ Best Practice:
# .env (NOT committed to git)
PRIVATE_KEY=abc123...
PEM_PASSWORD=strongpassword123
# .env.example (committed to git)
PRIVATE_KEY=your-private-key-here
PEM_PASSWORD=your-pem-password-here// Load safely
import 'dotenv/config'
const privateKey = process.env.PRIVATE_KEY
// Validate
if (!privateKey) {
throw new Error('PRIVATE_KEY environment variable not set')
}✅ Best Practice:
import { loadPrivateKeyFromPemFile } from '@klever/connect-crypto'
// Always use encrypted PEM files
const privateKey = loadPrivateKeyFromPemFile('./wallet.pem', password)
// Generate encrypted PEM (example)
// Use Klever CLI or other tools to generate encrypted PEM filesPEM File Security:
- ✅ Use strong passwords (16+ characters, mixed case, numbers, symbols)
- ✅ Store PEM files with restricted permissions (chmod 600)
- ✅ Never commit PEM files to version control
- ✅ Use different passwords for different environments
- ✅ Rotate passwords periodically
For production systems handling significant value:
// Use hardware wallet integration (when available)
import { LedgerWallet } from '@klever/connect-wallet' // Future implementation
const wallet = await LedgerWallet.connect()
const tx = await wallet.signTransaction(transaction)Implement key rotation for long-running services:
// Example key rotation strategy
interface KeyRotationPolicy {
rotateAfterDays: number
warnBeforeDays: number
}
function shouldRotateKey(keyCreatedAt: Date, policy: KeyRotationPolicy): boolean {
const daysSinceCreation = (Date.now() - keyCreatedAt.getTime()) / (1000 * 60 * 60 * 24)
return daysSinceCreation >= policy.rotateAfterDays
}Clear sensitive data from memory when done:
import { PrivateKeyImpl } from '@klever/connect-crypto'
async function signAndClear(data: Uint8Array, privateKeyHex: string) {
// Load key
const privateKey = PrivateKeyImpl.fromHex(privateKeyHex)
// Use key
const signature = await signMessage(data, privateKey)
// Clear key from memory (JavaScript limitation: can't guarantee)
// But at least remove references
privateKey.bytes.fill(0) // Zero out bytes
delete (privateKey as any).bytes // Remove reference
return signature
}Note: JavaScript has limitations on secure memory management. For high-security applications, consider:
- Using hardware wallets
- Implementing key derivation on-demand
- Running signing operations in isolated processes
Klever Connect SDK uses audited cryptographic libraries:
| Library | Purpose | Audit Status |
|---|---|---|
| @noble/ed25519 | Ed25519 signatures | ✅ Audited by Trail of Bits |
| @noble/hashes | Hash functions (SHA-512, Blake2b) | ✅ Audited by Trail of Bits |
| @scure/base | Base encoding | ✅ Security reviewed |
| @scure/bip39 | BIP39 mnemonics | ✅ Security reviewed |
| protobufjs | Protocol Buffers | ✅ Widely used, maintained |
Audit Reports: See audits/ directory (when available)
import { isKleverAddress } from '@klever/connect-core'
// Always validate addresses
if (!isKleverAddress(recipient)) {
throw new Error('Invalid recipient address')
}
// Validate amounts
if (amount <= 0n) {
throw new Error('Amount must be positive')
}
// Check balance before sending
const balance = await provider.getBalance(wallet.address)
if (balance < amount) {
throw new Error('Insufficient balance')
}// Build transaction
const tx = await TransactionBuilder.create(provider)
.sender(wallet.address)
.transfer({
receiver: recipient,
amount: amount,
})
.build()
// Review transaction before signing
console.log('Transaction details:')
console.log('- From:', tx.sender)
console.log('- To:', tx.contracts[0].parameter.receiver)
console.log('- Amount:', tx.contracts[0].parameter.amount)
console.log('- Nonce:', tx.nonce)
// Confirm with user (if interactive)
const confirmed = await confirm('Sign this transaction?')
if (!confirmed) throw new Error('Transaction cancelled')
// Sign and broadcast
await wallet.signTransaction(tx)
const hash = await provider.sendRawTransaction(tx.toHex())For contract interactions, test with queries first:
// Test readonly function first
const result = await contract.query('transfer', [recipient, amount])
// If successful, then invoke mutable function
const tx = await contract.invoke('transfer', [recipient, amount])import { KleverProvider } from '@klever/connect-provider'
// ✅ HTTPS endpoint
const provider = new KleverProvider({
network: {
nodeUrl: 'https://api.mainnet.klever.org',
},
})
// ❌ HTTP endpoint (insecure)
// const provider = new KleverProvider({
// network: {
// nodeUrl: 'http://api.mainnet.klever.org', // INSECURE!
// },
// })// Always wait for confirmation
const tx = await wallet.sendTransaction({ to: recipient, value: amount })
// Wait for receipt
const receipt = await tx.wait()
// Verify status
if (receipt.status !== 'success') {
console.error('Transaction failed:', receipt)
throw new Error('Transaction execution failed')
}
// Verify transaction hash matches
const onChainTx = await provider.getTransaction(receipt.hash)
if (!onChainTx) {
throw new Error('Transaction not found on chain')
}For public-facing applications:
// Implement rate limiting
const rateLimiter = new RateLimiter({
maxRequests: 100,
windowMs: 60000, // 1 minute
})
app.post('/api/transaction', rateLimiter.middleware, async (req, res) => {
// Handle transaction
})import { isValidABI } from '@klever/connect-contracts'
// Validate ABI before using
if (!isValidABI(abi)) {
throw new Error('Invalid contract ABI')
}import { Contract, ContractReceiptError } from '@klever/connect-contracts'
try {
const tx = await contract.invoke('transfer', [recipient, amount])
const receipt = await tx.wait()
// Check return code
if (receipt.returnCode !== 'Ok') {
console.error('Contract execution failed:', receipt.returnMessage)
}
} catch (error) {
if (error instanceof ContractReceiptError) {
console.error('Contract error:', error.message)
console.error('Return code:', error.returnCode)
console.error('Gas used:', error.gasUsed)
}
}// Always test on testnet first
const testnetProvider = new KleverProvider('testnet')
const testnetContract = new Contract(testnetAddress, abi, testnetWallet)
// Test all functions
await testnetContract.query('balanceOf', [address])
await testnetContract.invoke('transfer', [recipient, smallAmount])
// Monitor gas usage
const receipt = await tx.wait()
console.log('Gas used:', receipt.gasUsed)
// Only deploy to mainnet after thorough testingAdd CSP headers to prevent XSS:
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline'; connect-src 'self' https://api.mainnet.klever.org"
/>import { isKleverAddress } from '@klever/connect-core'
function validateUserInput(address: string): boolean {
// Sanitize input
const sanitized = address.trim()
// Validate format
if (!isKleverAddress(sanitized)) {
throw new Error('Invalid address format')
}
// Check length
if (sanitized.length < 62 || sanitized.length > 63) {
throw new Error('Invalid address length')
}
return true
}import { useKlever } from '@klever/connect-react'
import { useEffect, useState } from 'react'
function SecureTransferComponent() {
const { sendTransaction, account } = useKlever()
const [isConfirmed, setIsConfirmed] = useState(false)
const handleTransfer = async () => {
// Require explicit user confirmation
if (!isConfirmed) {
alert('Please confirm the transaction')
return
}
try {
// Validate inputs
if (!isKleverAddress(recipient)) throw new Error('Invalid recipient')
if (amount <= 0n) throw new Error('Invalid amount')
// Send transaction
const tx = await sendTransaction({ to: recipient, value: amount })
// Wait for confirmation
await tx.wait()
// Reset confirmation
setIsConfirmed(false)
} catch (error) {
console.error('Transaction failed:', error)
alert('Transaction failed: ' + error.message)
}
}
return (
<div>
{/* Show transaction details */}
<div>
<p>From: {account}</p>
<p>To: {recipient}</p>
<p>Amount: {amount}</p>
</div>
{/* Require confirmation */}
<label>
<input
type="checkbox"
checked={isConfirmed}
onChange={(e) => setIsConfirmed(e.target.checked)}
/>
I confirm this transaction
</label>
<button onClick={handleTransfer} disabled={!isConfirmed}>
Send Transaction
</button>
</div>
)
}# Check for updates
pnpm update --latest
# Audit dependencies
pnpm audit
# Fix vulnerabilities
pnpm audit --fixAlways commit lock files:
# Commit to version control
git add pnpm-lock.yaml package-lock.json yarn.lock# Verify checksums
pnpm install --frozen-lockfileIf you suspect a security breach:
- Rotate all keys immediately
- Revoke compromised credentials
- Review transaction history
- Notify affected users
- Contact security@klever.io
- Collect logs from all affected systems
- Identify attack vector
- Assess impact (funds lost, data exposed)
- Document findings
- Patch vulnerabilities
- Deploy fixes
- Monitor for further issues
- Update security documentation
Before deploying to production:
- All private keys stored securely (not hardcoded)
- Environment variables properly configured
- HTTPS endpoints used for all network requests
- Input validation implemented
- Transaction confirmation required for sensitive operations
- Error handling implemented
- Rate limiting enabled for public endpoints
- CSP headers configured (frontend)
- Dependencies audited and up-to-date
- Smart contracts tested on testnet
- Backup and recovery procedures documented
- Monitoring and alerting configured
- Incident response plan in place
- Klever Blockchain Security Guide
- Web3 Security Best Practices
- OWASP Cryptographic Storage Cheat Sheet
- Node.js Security Best Practices
For security concerns:
- Email: security@klever.io
- Bug Bounty: Coming soon
For general support:
- Forum: https://forum.klever.org
- Discord: https://discord.gg/klever
- GitHub Issues: https://github.com/klever-io/klever-connect/issues
Last Updated: October 2025 Next Review: January 2026