Security
Security Model
Every payment passes through six independent verification layers before any settlement action. A failure at any layer halts the payment — no partial settlements, no silent failures.
The 6-layer verification model
The transaction signature is fetched from a Solana RPC node and checked for confirmed or finalized status. If not yet propagated, Auron retries up to 4 times (12 s total) before failing.
Every transfer instruction is checked against the canonical USDC mint address — mainnet EPjFWdd5… or devnet Gh9ZwEmd…. Fake tokens that mimic USDC are rejected here.
The destination ATA is derived on-the-fly from the treasury wallet and USDC mint. The transfer must target this exact address. On mainnet this is a hard failure; on devnet it logs a warning and proceeds.
The on-chain USDC amount must match the quoted amount within ±2%. This covers rounding differences across wallets while blocking payments that are significantly short.
Transaction signatures are stored in Vercel KV after the first successful settlement. Any attempt to re-submit the same signature returns HTTP 409 instead of triggering a duplicate payout.
Each IP is limited to 10 payment attempts per minute. API key holders have higher per-key limits configured in the database. Human wallet users share the IP-based bucket.
NEXT_PUBLIC_SOLANA_NETWORK !== "mainnet-beta".Rate limits by endpoint
When a limit is exceeded, Auron returns 429 Too Many Requests with a Retry-After header indicating when the window resets.
Transaction verifier internals
The verifier inspects both top-level and inner instructions from the parsed transaction. This matters because Phantom routes USDC transfers through the Associated Token Program via CPI — the actual SPL transfer often appears only in innerInstructions.
C8F135">"color:#3F3F46">// Both top-level AND inner instructions are inspected
const topLevel = tx.transaction.message.instructions;
const inner = tx.meta?.innerInstructions?.flatMap(i => i.instructions) ?? [];
const all = [...topLevel, ...inner];
C8F135">"color:#3F3F46">// Both transfer types are accepted
if (parsed.type !== C8F135">"transferChecked" && parsed.type !== C8F135">"transfer") continue;
C8F135">"color:#3F3F46">// For transferChecked: verify USDC mint
if (parsed.type === C8F135">"transferChecked") {
if ((info.mint as F5A623">string) !== usdcMint) continue;
}/api/v1/pay before waiting for on-chain confirmation. Pass commitment: "confirmed" to confirmTransaction first — the verifier will retry but you burn 12 s before it fails.PIN security
User PINs are hashed with argon2id on the server via /api/hash-pin. The raw PIN never leaves the browser in plaintext. PIN hashes are excluded from localStorage persistence in the Zustand store via partialize.
API key storage
API keys are stored as SHA-256 hashes only. Auron never logs, stores, or transmits raw key values. To revoke a key, set is_active = false in the api_keys table — the hash becomes inactive immediately with no cache invalidation delay.
ak_live_xxx keys in client-side code or commit them to version control. Use process.env.AURON_API_KEY on your server only. A compromised live key can initiate payouts up to your daily spend limit.Transport security
- All traffic is TLS 1.2+ (enforced by Vercel edge)
Content-Security-Policyset todefault-src 'self'with explicit allowlistsX-Frame-Options: DENY— prevents clickjackingX-Content-Type-Options: nosniffReferrer-Policy: strict-origin-when-cross-origin
Responsible disclosure
Found a vulnerability? Email anirudhvashisth2006@gmail.com before public disclosure. We aim to acknowledge within 24 hours and resolve within 14 days for critical issues.