CodeVix Labs
Engineering Team
Most API security breaches aren't sophisticated zero-day exploits. They're the result of basic oversights: missing rate limits, unvalidated inputs, overly permissive CORS policies. This checklist covers the 10 most important things to lock down before your API goes live, based on OWASP guidelines and incidents we've seen firsthand.
1. Rate Limiting
Every public endpoint needs rate limiting. Every authenticated endpoint needs rate limiting. Every admin endpoint needs rate limiting. There are no exceptions.
Use sliding window algorithms rather than fixed counters — they're harder to game and provide smoother traffic shaping. Set different limits for different endpoint types: authentication endpoints should be heavily restricted (5-10 requests per minute), public read endpoints can be more generous (100-200/minute), and write operations should sit somewhere in between. Always return 429 Too Many Requests with a Retry-After header so clients can back off gracefully.
2. Input Validation
Validate at the boundary. Every piece of data that crosses into your API should be checked before it touches any business logic. Schema validation libraries like Zod or Joi make this straightforward — define a schema for each endpoint and reject requests that don't match.
Validate types, lengths, formats, and ranges. A string field that accepts 10MB of text is a denial-of-service vector. An integer field that accepts negative values might break your billing logic. An email field that doesn't validate format will corrupt your database. Be explicit about what you accept and reject everything else.
3. Authentication & Authorization
Use JWTs with short expiration times (15-60 minutes for access tokens) and refresh tokens for session continuity. Implement role-based access control and check permissions on every request — not just at the route level, but at the data level. A user should never be able to access another user's resources just by changing an ID in the URL.
Store refresh tokens securely (httpOnly cookies, not localStorage). Implement token revocation for logout and password changes. And always validate the NEXTAUTH_SECRET or equivalent signing key is sufficiently strong — at least 32 bytes of entropy.
4. HTTPS Everywhere
No exceptions. Every API endpoint, every webhook, every redirect must use HTTPS. Configure HSTS (HTTP Strict Transport Security) headers with a long max-age to prevent downgrade attacks. If you're using a platform like Vercel, HTTPS is automatic — but verify that your custom domains and API subdomains are also covered. A single HTTP endpoint in your infrastructure is a potential man-in-the-middle vector.
5. SQL Injection Prevention
This should be a solved problem in 2026, yet it remains in the OWASP Top 10 because developers still concatenate user input into query strings. The fix is simple: use parameterized queries or an ORM.
If you're using Prisma, TypeORM, or Drizzle, you're protected by default — these tools parameterize queries automatically. But watch for raw query escape hatches (prisma.$queryRaw, etc.). Audit every raw query in your codebase and ensure user input is never interpolated directly.
6. XSS Prevention
Cross-site scripting attacks inject malicious scripts through user-supplied data. Defend in layers: sanitize all user-generated content before rendering (use libraries like sanitize-html with explicit tag and attribute allowlists), set a strict Content Security Policy (CSP) header, and avoid dangerouslySetInnerHTML unless you've sanitized the input first.
Block style attributes and data: URIs in your sanitizer — both are common XSS vectors that bypass basic tag-level filtering.
7. CORS Configuration
Never use Access-Control-Allow-Origin: * on authenticated endpoints. Restrict origins explicitly to your frontend domain(s). If you need to support multiple origins (e.g., staging and production), validate the Origin header against an allowlist rather than reflecting it back. Misconfigured CORS is one of the most common vulnerabilities in modern web APIs — it effectively lets any website make authenticated requests on behalf of your users.
8. Error Handling
Your API should never expose stack traces, database queries, file paths, or internal service names in error responses. In development, detailed errors are helpful. In production, they're a roadmap for attackers.
Return consistent error shapes with generic messages ("Something went wrong", not "ECONNREFUSED 10.0.3.42:5432") and log the detailed error server-side where only your team can see it. Use structured logging with correlation IDs so you can trace errors back to specific requests.
9. Audit Logging
Log every write operation: who made the request, what changed, and when. This isn't just for security — it's essential for debugging, compliance, and incident response.
Store audit logs separately from application logs and make them append-only (immutable). Include the authenticated user ID, the action performed, the affected resource, a timestamp, and the request IP. When something goes wrong — and eventually it will — your audit log is the difference between a quick investigation and weeks of forensics.
10. Dependency Scanning
Your code is only as secure as your dependencies. Run npm audit in your CI pipeline and fail the build on critical vulnerabilities. Use tools like Dependabot or Renovate to keep dependencies updated automatically.
Review new dependencies before adding them: check download counts, maintenance activity, and the package's dependency tree. A single compromised transitive dependency can expose your entire application. The fewer dependencies you have, the smaller your attack surface.
Ready to discuss your project?
Book a free 15-minute technical audit with our engineering team.