Claude-code-plugins-plus-skills alchemy-security-basics
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/alchemy-pack/skills/alchemy-security-basics" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-alchemy-security-basics && rm -rf "$T"
manifest:
plugins/saas-packs/alchemy-pack/skills/alchemy-security-basics/SKILL.mdsource content
Alchemy Security Basics
Overview
Web3 security practices for Alchemy-powered applications: API key protection, private key management, input validation, and smart contract interaction safety.
Security Checklist
| Category | Requirement | Priority |
|---|---|---|
| API keys | Never expose in client-side code | Critical |
| Private keys | Use environment vars or secret manager | Critical |
| Addresses | Validate and checksum all inputs | High |
| RPC calls | Never pass user input directly to RPC | High |
| Webhooks | Verify HMAC signatures | High |
| Dependencies | Audit npm packages for supply chain | Medium |
Instructions
Step 1: API Key Protection
// WRONG — API key in frontend code // const alchemy = new Alchemy({ apiKey: 'demo123' }); // NEVER DO THIS // RIGHT — API key in backend proxy // src/api/proxy.ts import express from 'express'; import { Alchemy, Network } from 'alchemy-sdk'; const app = express(); const alchemy = new Alchemy({ apiKey: process.env.ALCHEMY_API_KEY, // Server-side only network: Network.ETH_MAINNET, }); // Proxy endpoint — frontend calls this instead of Alchemy directly app.get('/api/balance/:address', async (req, res) => { const { address } = req.params; if (!/^0x[a-fA-F0-9]{40}$/.test(address)) { return res.status(400).json({ error: 'Invalid address format' }); } const balance = await alchemy.core.getBalance(address); res.json({ balance: balance.toString() }); }); // Alchemy Dashboard: restrict API key to specific domains/IPs // Dashboard > App > Settings > Allowed Domains
Step 2: Input Validation for Blockchain Queries
// src/security/validators.ts import { ethers } from 'ethers'; function validateAddress(input: string): string { if (!ethers.isAddress(input)) throw new Error(`Invalid address: ${input}`); return ethers.getAddress(input); // Returns checksummed address } function validateBlockNumber(input: string | number): string { if (input === 'latest' || input === 'pending' || input === 'earliest') return input; const num = typeof input === 'string' ? parseInt(input) : input; if (isNaN(num) || num < 0) throw new Error(`Invalid block number: ${input}`); return `0x${num.toString(16)}`; } function validateTokenId(input: string): string { if (!/^\d+$/.test(input) && !input.startsWith('0x')) { throw new Error(`Invalid token ID: ${input}`); } return input; } export { validateAddress, validateBlockNumber, validateTokenId };
Step 3: Private Key Safety
// src/security/wallet-safety.ts // NEVER: // - Hardcode private keys in source code // - Log private keys or mnemonic phrases // - Store private keys in .env files committed to git // - Accept private keys from user input in a web app // Safe wallet setup for server-side operations import { ethers } from 'ethers'; import { Alchemy, Network } from 'alchemy-sdk'; async function createSafeWallet() { const alchemy = new Alchemy({ apiKey: process.env.ALCHEMY_API_KEY, network: Network.ETH_SEPOLIA, }); const provider = await alchemy.config.getProvider(); // Load private key from secret manager (GCP example) const { SecretManagerServiceClient } = await import('@google-cloud/secret-manager'); const client = new SecretManagerServiceClient(); const [version] = await client.accessSecretVersion({ name: `projects/${process.env.GCP_PROJECT}/secrets/deployer-private-key/versions/latest`, }); const privateKey = version.payload?.data?.toString() || ''; const wallet = new ethers.Wallet(privateKey, provider); return wallet; }
Step 4: Webhook Signature Verification
// src/security/webhook-verify.ts import crypto from 'crypto'; function verifyAlchemyWebhookSignature( body: string, signature: string, signingKey: string, ): boolean { const hmac = crypto.createHmac('sha256', signingKey); hmac.update(body, 'utf8'); const expectedSig = hmac.digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSig), ); }
Output
- API key proxy pattern (never expose to client)
- Input validation for addresses, blocks, and token IDs
- Private key loaded from secret manager
- Webhook HMAC signature verification
Resources
Next Steps
For production deployment, see
alchemy-prod-checklist.