Home/Blog/Cybersecurity/API Documentation Security: Protecting Sensitive Information in OpenAPI Specs
Cybersecurity

API Documentation Security: Protecting Sensitive Information in OpenAPI Specs

Secure your API documentation by protecting sensitive endpoints, sanitizing examples, and implementing proper access controls for Swagger/OpenAPI specs.

By Inventive HQ Team
API Documentation Security: Protecting Sensitive Information in OpenAPI Specs

API documentation is essential for developers but can become a security liability if it exposes sensitive information. This guide covers securing OpenAPI/Swagger specifications and documentation portals.

Documentation Security Risks

┌─────────────────────────────────────────────────────────────────────────────┐
│                  INFORMATION DISCLOSED IN API DOCS                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  PUBLIC DOCS LEAKING...                    ATTACKER USES FOR...             │
│  ─────────────────────────────────────────────────────────────────────────  │
│                                                                              │
│  • Admin endpoint paths                    → Direct exploitation            │
│  • Internal endpoint patterns              → Endpoint enumeration           │
│  • Authentication mechanisms               → Auth bypass research           │
│  • Parameter validation rules              → Boundary testing               │
│  • Rate limit thresholds                   → DoS planning                   │
│  • Error message formats                   → Error-based attacks            │
│  • Data model structures                   → SQL/NoSQL injection            │
│  • Real example data (PII)                 → Social engineering             │
│  • Version numbers                         → Known CVE exploitation         │
│  • Internal hostnames                      → Network mapping                │
│                                                                              │
│  DOCUMENTATION IS RECONNAISSANCE                                            │
│  Attackers read your docs before attacking your API                        │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Tiered Documentation Strategy

Separate Specs for Different Audiences

# public-openapi.yaml - External developers
openapi: 3.1.0
info:
  title: MyApp Public API
  version: 1.0.0

paths:
  /users:
    get:
      summary: List users
      # Public endpoints only
  /products:
    get:
      summary: List products

# No admin endpoints, no internal routes
# internal-openapi.yaml - Internal developers only
openapi: 3.1.0
info:
  title: MyApp Internal API
  version: 1.0.0

paths:
  # Public endpoints
  /users:
    get:
      summary: List users

  # Internal endpoints marked
  /admin/users:
    x-internal: true
    get:
      summary: Admin user management

  /internal/metrics:
    x-internal: true
    get:
      summary: System metrics

  /debug/cache:
    x-internal: true
    delete:
      summary: Clear cache

Build-Time Filtering

// scripts/filter-openapi.ts
import { OpenAPIV3 } from 'openapi-types';
import yaml from 'js-yaml';
import fs from 'fs';

function filterInternalEndpoints(spec: OpenAPIV3.Document): OpenAPIV3.Document {
  const filtered = { ...spec, paths: {} };

  for (const [path, pathItem] of Object.entries(spec.paths || {})) {
    // Skip paths marked as internal
    if ((pathItem as any)['x-internal']) {
      continue;
    }

    // Skip individual operations marked as internal
    const filteredPathItem: OpenAPIV3.PathItemObject = {};
    for (const [method, operation] of Object.entries(pathItem || {})) {
      if (method.startsWith('x-')) continue;
      if ((operation as any)['x-internal']) continue;

      filteredPathItem[method as keyof OpenAPIV3.PathItemObject] = operation;
    }

    if (Object.keys(filteredPathItem).length > 0) {
      filtered.paths[path] = filteredPathItem;
    }
  }

  // Also filter schemas marked as internal
  if (filtered.components?.schemas) {
    for (const [name, schema] of Object.entries(filtered.components.schemas)) {
      if ((schema as any)['x-internal']) {
        delete filtered.components.schemas[name];
      }
    }
  }

  return filtered;
}

// Generate public spec
const internalSpec = yaml.load(
  fs.readFileSync('./openapi-internal.yaml', 'utf8')
) as OpenAPIV3.Document;

const publicSpec = filterInternalEndpoints(internalSpec);

fs.writeFileSync(
  './public/openapi.yaml',
  yaml.dump(publicSpec)
);

console.log('Generated filtered public OpenAPI spec');

Sanitizing Examples

Fake Data Guidelines

# ❌ BAD - Real or realistic data
examples:
  user:
    value:
      id: 12847293
      email: [email protected]
      phone: +1-555-123-4567
      ssn: "123-45-6789"
      address: "123 Main St, San Francisco, CA 94102"
      api_key: "sk_live_51ABC123DEF456..."

# ✅ GOOD - Obviously fake data
examples:
  user:
    value:
      id: 123
      email: [email protected]
      phone: "+1-555-000-0000"
      ssn: "000-00-0000"
      address: "742 Evergreen Terrace, Springfield"
      api_key: "your-api-key-here"

Automated Example Generation

import { faker } from '@faker-js/faker';

// Generate safe fake data for examples
function generateSafeExample(schema: any): any {
  if (schema.type === 'string') {
    if (schema.format === 'email') {
      return '[email protected]';
    }
    if (schema.format === 'uri') {
      return 'https://example.com/path';
    }
    if (schema.format === 'uuid') {
      return '00000000-0000-0000-0000-000000000000';
    }
    if (schema.format === 'date-time') {
      return '2025-01-01T00:00:00Z';
    }
    if (schema.enum) {
      return schema.enum[0];
    }
    return 'string';
  }

  if (schema.type === 'integer' || schema.type === 'number') {
    return schema.minimum || 0;
  }

  if (schema.type === 'boolean') {
    return true;
  }

  if (schema.type === 'array') {
    return [generateSafeExample(schema.items)];
  }

  if (schema.type === 'object') {
    const obj: any = {};
    for (const [key, propSchema] of Object.entries(schema.properties || {})) {
      obj[key] = generateSafeExample(propSchema);
    }
    return obj;
  }

  return null;
}

CI Check for Sensitive Data

// scripts/check-openapi-pii.ts
import yaml from 'js-yaml';
import fs from 'fs';

const PII_PATTERNS = [
  /\b[A-Za-z0-9._%+-]+@(?!example\.com)[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/i, // Real emails
  /\b\d{3}-\d{2}-\d{4}\b/, // SSN format (not 000-00-0000)
  /\bsk_live_\w+/, // Live Stripe keys
  /\b(password|secret|token)["']?\s*[:=]\s*["'][^"']+["']/i, // Credentials
  /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/, // Internal IPs
  /\b10\.\d+\.\d+\.\d+/, // Private IPs
  /\b192\.168\.\d+\.\d+/, // Private IPs
];

function checkForPII(obj: any, path: string = ''): string[] {
  const issues: string[] = [];

  if (typeof obj === 'string') {
    for (const pattern of PII_PATTERNS) {
      if (pattern.test(obj)) {
        issues.push(`Potential PII at ${path}: "${obj.slice(0, 50)}..."`);
      }
    }
  } else if (Array.isArray(obj)) {
    obj.forEach((item, i) => {
      issues.push(...checkForPII(item, `${path}[${i}]`));
    });
  } else if (typeof obj === 'object' && obj !== null) {
    for (const [key, value] of Object.entries(obj)) {
      issues.push(...checkForPII(value, `${path}.${key}`));
    }
  }

  return issues;
}

// Run check
const spec = yaml.load(fs.readFileSync('./openapi.yaml', 'utf8'));
const issues = checkForPII(spec);

if (issues.length > 0) {
  console.error('PII detected in OpenAPI spec:');
  issues.forEach(issue => console.error(`  - ${issue}`));
  process.exit(1);
}

console.log('No PII detected in OpenAPI spec');

Securing Swagger UI

Disable in Production

import express from 'express';
import swaggerUi from 'swagger-ui-express';
import swaggerDocument from './openapi.json';

const app = express();

// Only enable Swagger UI in development
if (process.env.NODE_ENV !== 'production') {
  app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
}

// In production, serve static docs or redirect to docs site
if (process.env.NODE_ENV === 'production') {
  app.get('/docs', (req, res) => {
    res.redirect('https://docs.example.com');
  });
}

Authenticated Swagger UI

import basicAuth from 'express-basic-auth';

// Protect Swagger UI with authentication
const swaggerAuth = basicAuth({
  users: { admin: process.env.SWAGGER_PASSWORD! },
  challenge: true,
  realm: 'API Documentation',
});

app.use('/docs', swaggerAuth, swaggerUi.serve, swaggerUi.setup(swaggerDocument));

Read-Only Mode (Disable Try It Out)

const swaggerOptions = {
  swaggerOptions: {
    supportedSubmitMethods: [], // Disable all "Try it out" methods
    // Or limit to safe methods only:
    // supportedSubmitMethods: ['get', 'head', 'options'],
  },
};

app.use(
  '/docs',
  swaggerUi.serve,
  swaggerUi.setup(swaggerDocument, swaggerOptions)
);

Access Control for Documentation

Tiered Access

interface DocsUser {
  id: string;
  tier: 'public' | 'partner' | 'internal';
}

const specs = {
  public: publicOpenApiSpec,
  partner: partnerOpenApiSpec,
  internal: internalOpenApiSpec,
};

app.get('/openapi.json', authenticate, (req, res) => {
  const user = req.user as DocsUser | undefined;

  // Default to public spec for unauthenticated
  const tier = user?.tier || 'public';
  const spec = specs[tier];

  res.json(spec);
});

app.use('/docs', authenticate, (req, res, next) => {
  const user = req.user as DocsUser | undefined;
  const tier = user?.tier || 'public';

  // Serve Swagger UI with appropriate spec
  swaggerUi.setup(specs[tier])(req, res, next);
});

Robots.txt and Noindex

# robots.txt
User-agent: *
Disallow: /docs/
Disallow: /swagger/
Disallow: /openapi.json
Disallow: /api-docs/
Disallow: /redoc/
<!-- Documentation pages -->
<meta name="robots" content="noindex, nofollow">
// Middleware to add noindex header
app.use('/docs', (req, res, next) => {
  res.setHeader('X-Robots-Tag', 'noindex, nofollow');
  next();
});

Security Scheme Documentation

Proper Security Scheme Examples

components:
  securitySchemes:
    # ✅ GOOD - Clear without over-revealing
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        JWT token obtained from /auth/login endpoint.
        Include in Authorization header: `Bearer <token>`

    # ✅ GOOD - API Key documentation
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        API key provided in your developer dashboard.
        Contact [email protected] to request access.

    # ❌ BAD - Too much detail
    OAuth2Bad:
      type: oauth2
      description: |
        OAuth2 with authorization code flow.
        Client secret is validated using HMAC-SHA256.
        Tokens are stored in Redis with 1-hour TTL.
        Bypass rate limiting by setting X-Internal: true header.

Error Message Sanitization

# OpenAPI error response documentation

components:
  schemas:
    # ✅ GOOD - Generic error without implementation details
    Error:
      type: object
      properties:
        error:
          type: string
          description: Error code
          example: "VALIDATION_ERROR"
        message:
          type: string
          description: Human-readable message
          example: "Invalid email format"
        request_id:
          type: string
          description: Correlation ID for support
          example: "req_abc123"

    # ❌ BAD - Exposes implementation
    BadError:
      type: object
      properties:
        error:
          example: "MongoError: E11000 duplicate key error"
        stack:
          example: "at UserModel.save (/app/src/models/user.js:45:12)"
        query:
          example: "SELECT * FROM users WHERE id = '1; DROP TABLE users;--'"

Documentation Review Checklist

┌─────────────────────────────────────────────────────────────────────────────┐
│                    DOCUMENTATION SECURITY CHECKLIST                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  SENSITIVE ENDPOINTS                                                        │
│  [ ] Admin endpoints not in public docs                                     │
│  [ ] Debug/test endpoints excluded                                          │
│  [ ] Internal-only routes filtered                                          │
│  [ ] Deprecated endpoints marked (not hidden)                               │
│                                                                              │
│  EXAMPLE DATA                                                               │
│  [ ] No real email addresses                                                │
│  [ ] No real phone numbers                                                  │
│  [ ] No real addresses or locations                                         │
│  [ ] No real API keys or tokens                                             │
│  [ ] No real user IDs or account numbers                                    │
│  [ ] Placeholder tokens clearly fake                                        │
│                                                                              │
│  SECURITY DETAILS                                                           │
│  [ ] No implementation details exposed                                      │
│  [ ] No version numbers of dependencies                                     │
│  [ ] No internal hostnames or IPs                                           │
│  [ ] Rate limits documented generically                                     │
│  [ ] Error formats don't reveal internals                                   │
│                                                                              │
│  ACCESS CONTROL                                                             │
│  [ ] Swagger UI disabled or protected in prod                               │
│  [ ] OpenAPI spec access controlled                                         │
│  [ ] Documentation pages have noindex                                       │
│  [ ] robots.txt blocks crawlers                                             │
│                                                                              │
│  REVIEW PROCESS                                                             │
│  [ ] Security review before publishing                                      │
│  [ ] CI checks for PII in examples                                          │
│  [ ] Separate specs for different audiences                                 │
│  [ ] Regular audits of published docs                                       │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Best Practices

  1. Separate specs - Different detail levels for different audiences
  2. Filter at build time - Remove internal endpoints before publishing
  3. Fake examples - Obviously fake data in all examples
  4. Automate checks - CI pipeline scans for PII
  5. Protect Swagger UI - Auth or disable in production
  6. Block crawlers - robots.txt and noindex
  7. Minimal security details - Document what, not how
  8. Review process - Security review before publishing
  9. Version consistency - Docs match deployed API version
  10. Monitor exposure - Alert on indexed documentation pages

Next Steps

Don't wait for a breach to act

Get a free security assessment. Our experts will identify your vulnerabilities and create a protection plan tailored to your business.

Formal Security Models Explained: Bell-LaPadula, Biba, Clark-Wilson, and Beyond

Formal Security Models Explained: Bell-LaPadula, Biba, Clark-Wilson, and Beyond

Master the formal security models that underpin all access control systems. This comprehensive guide covers Bell-LaPadula, Biba, Clark-Wilson, Brewer-Nash, lattice-based access control, and how to choose the right model for your organization.

Biometric Authentication: Understanding FAR, FRR, and CER for Security Professionals

Biometric Authentication: Understanding FAR, FRR, and CER for Security Professionals

Master the critical metrics behind biometric authentication systems including False Acceptance Rate (FAR), False Rejection Rate (FRR), and Crossover Error Rate (CER). Learn how to evaluate, tune, and deploy biometric systems across enterprise, consumer, and high-security environments.

Database Inference & Aggregation Attacks: The Complete Defense Guide

Database Inference & Aggregation Attacks: The Complete Defense Guide

Learn how inference and aggregation attacks exploit aggregate queries and combined data to reveal protected information, and discover proven countermeasures including differential privacy, polyinstantiation, and query restriction controls.

NIST 800-88 Media Sanitization Complete Guide: Clear, Purge, and Destroy Methods Explained

NIST 800-88 Media Sanitization Complete Guide: Clear, Purge, and Destroy Methods Explained

Master NIST SP 800-88 Rev. 1 media sanitization methods including Clear, Purge, and Destroy. Covers SSD vs HDD sanitization, crypto erase, degaussing, regulatory compliance, and building a media sanitization program.

Physical Security & CPTED: The Complete Guide to Protecting Facilities, Data Centers, and Critical Assets

Physical Security & CPTED: The Complete Guide to Protecting Facilities, Data Centers, and Critical Assets

A comprehensive guide to physical security covering CPTED principles, security zones, access control, fire suppression, and environmental controls for protecting facilities and data centers.

Threat Modeling with STRIDE and DREAD: A Complete Guide to Proactive Security Architecture

Threat Modeling with STRIDE and DREAD: A Complete Guide to Proactive Security Architecture

Master threat modeling with STRIDE and DREAD frameworks to identify, classify, and prioritize security threats before they become vulnerabilities. This comprehensive guide covers data flow diagrams, mitigation mappings, MITRE ATT&CK integration, and building an enterprise threat modeling program.