This is a sample deliverable. It shows the format and depth of a $200 code review. The codebase and findings are illustrative, based on common patterns I encounter.
A printable 1-page checklist covering security, performance, testing, and more.
Code Review Report
Project: acme-api • Reviewed: March 2026 • Reviewer: Owen Devereaux
Executive Summary
I reviewed approximately 3,200 lines of TypeScript across 47 files in the acme-api repository, focusing on security, performance, and maintainability.
Overall assessment: The codebase is functional but has several security vulnerabilities that should be addressed before production deployment. The architecture is reasonable, though there are opportunities to reduce duplication and improve test reliability.
Priority Actions
- Fix SQL injection vulnerability (SEC-001) — This is exploitable and should be patched immediately.
- Add rate limiting to auth endpoints (SEC-002) — Prevents brute force attacks.
- Optimize N+1 queries (PERF-001) — Will significantly improve response times at scale.
Findings Summary
| ID | Severity | Category | Title |
|---|---|---|---|
| SEC-001 | Critical | Security | SQL Injection vulnerability in user search |
| SEC-002 | High | Security | Missing rate limiting on authentication endpoints |
| PERF-001 | High | Performance | N+1 query pattern in order listing |
| MAINT-001 | Medium | Maintainability | Duplicated validation logic across handlers |
| MAINT-002 | Medium | Maintainability | Magic numbers in business logic |
| ERR-001 | Medium | Error Handling | Swallowed exceptions in async handlers |
| TEST-001 | Low | Testing | Integration tests share database state |
| DOC-001 | Low | Documentation | Missing JSDoc on public API functions |
Detailed Findings
SQL Injection vulnerability in user search
SEC-001Location: src/services/userService.ts:47
User input is directly interpolated into SQL query without parameterization. An attacker could extract or modify database contents.
Recommendation: Use parameterized queries or an ORM query builder.
// ❌ Vulnerable to SQL injection
const query = `SELECT * FROM users WHERE name LIKE '%${searchTerm}%'`;
const results = await db.raw(query);// ✅ Parameterized query
const results = await db('users')
.where('name', 'like', `%${searchTerm}%`);Missing rate limiting on authentication endpoints
SEC-002Location: src/routes/auth.ts
Login and password reset endpoints have no rate limiting, enabling brute force attacks.
Recommendation: Add rate limiting middleware (e.g., express-rate-limit) with appropriate thresholds.
// ❌ No rate limiting
router.post('/login', loginHandler);// ✅ With rate limiting
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 attempts per window
message: 'Too many login attempts'
});
router.post('/login', loginLimiter, loginHandler);N+1 query pattern in order listing
PERF-001Location: src/services/orderService.ts:23
Each order triggers a separate database query for customer data. With 100 orders, this results in 101 queries.
Recommendation: Use eager loading or batch the customer lookup.
// ❌ N+1 queries
const orders = await Order.findAll();
for (const order of orders) {
order.customer = await Customer.findById(order.customerId);
}// ✅ Single query with join
const orders = await Order.findAll({
include: [{ model: Customer, as: 'customer' }]
});Duplicated validation logic across handlers
MAINT-001Location: src/handlers/*.ts
Email and phone validation is copy-pasted across 7 different files. Changes require updates in multiple places.
Recommendation: Extract to a shared validation utility or use a schema validation library like Zod.
Magic numbers in business logic
MAINT-002Location: src/services/pricingService.ts
Discount percentages and thresholds are hardcoded (0.15, 1000, etc.) without explanation.
Recommendation: Extract to named constants or configuration.
// ❌ Magic numbers
if (total > 1000) {
discount = total * 0.15;
}// ✅ Named constants
const BULK_DISCOUNT_THRESHOLD = 1000;
const BULK_DISCOUNT_RATE = 0.15;
if (total > BULK_DISCOUNT_THRESHOLD) {
discount = total * BULK_DISCOUNT_RATE;
}Swallowed exceptions in async handlers
ERR-001Location: src/handlers/webhookHandler.ts:34
Catch block logs error but doesn't propagate it. Failures appear successful to callers.
Recommendation: Re-throw or return error response after logging.
Integration tests share database state
TEST-001Location: tests/integration/*.test.ts
Tests don't reset database between runs, causing flaky failures when run in different orders.
Recommendation: Add beforeEach hook to reset test database or use transactions.
Missing JSDoc on public API functions
DOC-001Location: src/api/*.ts
Public functions lack documentation for parameters and return values.
Recommendation: Add JSDoc comments, especially for functions used by other modules.
Get a review like this for your codebase
$200 flat rate. Delivered in 48 hours. No surprises.
Request a Code Review