Fix Shadow API Exposure in Koa
Shadow APIs are undocumented, unmonitored endpoints lurking in your production environment—often legacy routes or debug hooks that bypass standard security controls. In Koa, this typically happens when developers mount routers without global middleware or leave 'ghost' routes active. To kill shadow APIs, you must enforce a 'Deny by Default' architecture and centralize route discovery.
The Vulnerable Pattern
const Koa = require('koa'); const Router = require('@koa/router'); const app = new Koa(); const router = new Router();// Official API route with some protection logic inside router.get(‘/api/v2/data’, (ctx) => { ctx.body = { status: ‘secure’ }; });
// SHADOW API: Legacy endpoint left active, undocumented, and bypassing global checks // Attackers find this via fuzzing or JS source mapping router.get(‘/old-api/v1/debug-internal’, (ctx) => { ctx.body = { db_connection: ‘exposed_credentials_here’ }; });
app.use(router.routes()); app.listen(3000);
The Secure Implementation
To eliminate Shadow APIs in Koa: 1. Use Router Prefixes to force all traffic through a known namespace. 2. Apply security middleware (Auth/Rate-limiting) at the app-level or router-level before any routes are defined; this ensures 'ghost' routes can't bypass checks. 3. Implement a strict 'Deny by Default' policy by adding a final middleware to catch and kill any requests to unmapped paths. 4. Conduct regular code audits to prune legacy routes that are no longer documented in your OpenAPI/Swagger specs.
const Koa = require('koa'); const Router = require('@koa/router'); const app = new Koa();// 1. Define a strict router with a versioned prefix const apiRouter = new Router({ prefix: ‘/api/v2’ });
// 2. Enforce Global Security Middleware BEFORE the router const secureLayer = async (ctx, next) => { if (!ctx.headers[‘x-api-key’]) return ctx.throw(401, ‘Unauthorized’); await next(); };
apiRouter.use(secureLayer); apiRouter.get(‘/data’, (ctx) => { ctx.body = { status: ‘secure’ }; });
// 3. Explicitly mount only the hardened router app.use(apiRouter.routes()); app.use(apiRouter.allowedMethods());
// 4. Catch-all for unmapped routes (Deny by Default) app.use(ctx => { ctx.status = 404; ctx.body = { error: ‘Endpoint not found or deprecated’ }; });
app.listen(3000);
Your Koa API
might be exposed to Shadow API Exposure
74% of Koa apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.