Publicly accessible API documentation — Swagger UI, Redoc, GraphQL Playground — hands attackers a complete, interactive map of your API surface. CWE-200 (Exposure of Sensitive Information) and OWASP API Security Top 10 2023 API8 (Security Misconfiguration) both target documentation exposure as a misconfiguration that eliminates reconnaissance effort. Schema docs reveal endpoint names, parameter types, authentication methods, and sometimes internal implementation details through field names and descriptions. Attackers use publicly available Swagger specs to auto-generate exploit code targeting specific endpoints. Intentionally public APIs (developer platforms, open standards) are a legitimate exception — but this must be a deliberate choice, not a default.
Info severity because documentation exposure doesn't enable exploitation alone, but it reduces the effort of every subsequent attack by providing an interactive schema map.
Gate API documentation behind authentication middleware or restrict it to internal IP ranges. Disable interactive exploration (GraphQL Playground, Swagger's 'Try it out') in production entirely.
// Express + Swagger UI
import swaggerUi from 'swagger-ui-express'
import spec from './openapi.json'
// Apply admin-only auth middleware before mounting the docs
app.use(
'/api/docs',
requireAuth,
requireRole('admin'),
swaggerUi.serve,
swaggerUi.setup(spec, {
swaggerOptions: { tryItOutEnabled: false } // disable interactive execution
})
)
// Or disable entirely in production and ship docs to a separate internal tool:
if (process.env.NODE_ENV !== 'production') {
app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(spec))
}
If documentation must be public (developer platform), scrub internal endpoints and strip sensitive field descriptions before generating the public spec.
ID: api-security.design-security.documentation-security
Severity: info
What to look for: Enumerate every relevant item. Check whether API documentation (Swagger/OpenAPI, GraphQL schema playground) is publicly accessible or restricted to authenticated users. In production, API documentation should not expose internal endpoints or schema details to unauthenticated users.
Pass criteria: At least 1 of the following conditions is met. API documentation is either private (requires authentication), uses a whitelist of trusted IPs, or does not expose sensitive internal endpoints.
Fail criteria: Full API documentation is publicly accessible, exposing all endpoints and schema details to potential attackers.
Skip (N/A) when: The API is public-facing and documentation is intentionally public.
Detail on fail: "Swagger UI accessible at /api/docs with no authentication — full API schema exposed" or "GraphQL playground available in production — schema introspection enabled"
Remediation: Restrict documentation access:
// Protect Swagger UI
const swaggerUi = require('swagger-ui-express')
app.use('/api/docs', authMiddleware, swaggerUi.serve)
app.get('/api/docs', authMiddleware, swaggerUi.setup(spec))
// Or use IP allowlist for internal networks
const allowedIps = ['10.0.0.0/8', '172.16.0.0/12']
const ipWhitelist = (req, res, next) => {
if (!isIpInRange(req.ip, allowedIps)) {
return res.status(403).json({ error: 'Access denied' })
}
next()
}
app.use('/api/docs', ipWhitelist, swaggerUi.serve)