What OWASP Top 10 Means for API Developers
The OWASP API Security Top 10 is not the same as the original Top 10.
APIs have different attack surfaces. Here's what each one means in practice for a Next.js API developer.
API1: Broken Object Level Authorization (BOLA)
// VULNERABLE -- anyone can read anyone's data
// GET /api/orders/[id]
export async function GET(req: Request, { params }: { params: { id: string } }) {
const order = await db.order.findUnique({ where: { id: params.id } })
return Response.json(order) // Returns any order to any authenticated user!
}
// FIXED -- verify ownership
export async function GET(req: Request, { params }: { params: { id: string } }) {
const session = await getServerSession(authOptions)
if (!session) return Response.json({ error: 'Unauthorized' }, { status: 401 })
const order = await db.order.findFirst({
where: { id: params.id, userId: session.user.id } // Scoped to current user
})
if (!order) return Response.json({ error: 'Not found' }, { status: 404 })
return Response.json(order)
}
API2: Broken Authentication
// VULNERABLE -- weak token
const token = Buffer.from(`${userId}:${Date.now()}`).toString('base64')
// Predictable, not signed, can be forged
// FIXED -- signed JWT
import { SignJWT } from 'jose'
const secret = new TextEncoder().encode(process.env.JWT_SECRET)
const token = await new SignJWT({ userId })
.setProtectedHeader({ alg: 'HS256' })
.setExpirationTime('1h')
.sign(secret)
// Or just use NextAuth -- it handles this correctly by default
API3: Broken Object Property Level Authorization
// VULNERABLE -- returns all fields including sensitive ones
const user = await db.user.findUnique({ where: { id } })
return Response.json(user) // Includes passwordHash, stripeCustomerId, etc.
// FIXED -- select only what's safe to expose
const user = await db.user.findUnique({
where: { id },
select: { id: true, name: true, email: true, plan: true, createdAt: true }
// Excludes: passwordHash, stripeCustomerId, internalNotes
})
API4: Unrestricted Resource Consumption
// VULNERABLE -- no limits
const items = await db.item.findMany() // Returns 10,000 records
// FIXED -- pagination + limits
const { page = 1, limit = 20 } = SearchSchema.parse(searchParams)
const items = await db.item.findMany({
take: Math.min(limit, 100), // Hard cap at 100
skip: (page - 1) * limit,
})
// Also: rate limit expensive operations
// Also: limit file upload sizes (next.config.js sizeLimit)
// Also: timeout slow operations
API5: Broken Function Level Authorization
// VULNERABLE -- admin functions accessible to regular users
// DELETE /api/admin/users/[id]
export async function DELETE(req: Request, { params }) {
const session = await getServerSession(authOptions)
if (!session) return Response.json({ error: 'Unauthorized' }, { status: 401 })
// Checks auth but not admin role!
await db.user.delete({ where: { id: params.id } })
}
// FIXED
if (session.user.role !== 'admin') {
return Response.json({ error: 'Forbidden' }, { status: 403 })
}
API7: Server Side Request Forgery (SSRF)
// VULNERABLE -- fetches any URL the user provides
const { url } = await req.json()
const response = await fetch(url) // Could hit internal services!
// FIXED -- validate URL before fetching
import { z } from 'zod'
const Schema = z.object({
url: z.string().url().refine(url => {
const { hostname, protocol } = new URL(url)
return protocol === 'https:' &&
!['localhost', '127.0.0.1', '0.0.0.0', '169.254.169.254'].includes(hostname) &&
!hostname.startsWith('192.168.') &&
!hostname.startsWith('10.')
}, 'Invalid URL')
})
API8: Security Misconfiguration
// Common misconfigurations:
// 1. Detailed error messages in production
catch (error) {
// WRONG:
return Response.json({ error: error.message, stack: error.stack }, { status: 500 })
// RIGHT:
logger.error({ error }, 'Internal error')
return Response.json({ error: 'Internal server error' }, { status: 500 })
}
// 2. Debug endpoints in production
if (process.env.NODE_ENV !== 'production') {
// Only expose debug routes in dev
}
// 3. Missing security headers
// next.config.js headers() -- add CSP, HSTS, X-Frame-Options
MCP APIs and OWASP
MCP servers expose function-like APIs. BOLA, auth bypass, and resource consumption are all relevant attack surfaces -- the MCP Security Scanner checks for all of them.
$29/mo at whoffagents.com
Top comments (0)