API documentation security is the part of an API program that many teams never audit. You may harden the API with auth, rate limits, and security tests, while the OpenAPI spec, Swagger UI page, and auth-flow markdown live in a Git repo or static host that has not been reviewed since launch. On May 20, 2026, GitHub confirmed that attackers stole data from roughly 3,800 internal code repositories after a poisoned VS Code extension was installed on a GitHub employee’s laptop. That incident is a practical reminder to audit your own docs pipeline: if someone quietly changed your published API docs, would you or your consumers notice?
TL;DR
Secure API documentation means your docs have:
- Access control
- Version history
- Verifiable integrity
- An audit trail
Docs-as-code in Git can work well when the API is public, access is tightly controlled, reviews are enforced, and the published docs match the reviewed source. It becomes risky when specs are public by accident, stale, hand-maintained, or served from static hosts without access control.
A managed documentation layer like Apidog adds password protection, IP and email allowlists, custom domains, versioning, and documentation generated from your API design as the source of truth.
Why the GitHub breach should make you audit your API docs
The GitHub incident is worth looking at from an API documentation angle. The threat group TeamPCP exfiltrated GitHub-internal repositories and reportedly offered the dataset for more than $50,000 on an underground forum. BleepingComputer’s coverage says the malicious VS Code extension came from the official marketplace and ran on an employee device. GitHub said it found no evidence that customer data stored outside its internal repos was affected, and the investigation is ongoing.
For API teams, the lesson is not “panic about GitHub.” The lesson is: audit where your API docs live.
Common documentation setups look like this:
- An OpenAPI file in a Git repo
- CI builds Swagger UI or Redoc
- A static host serves the generated docs
- A CNAME points developers to the site
- Nobody reviews the setup again
That is a problem because API docs are executable instructions in practice. Developers copy endpoint URLs, request bodies, auth headers, OAuth flows, and code samples directly into services. If an attacker changes those instructions, they are not just editing a web page. They are influencing code that may run in production.
A similar pattern appears in other breach reviews. For example, this writeup on API security lessons from the Vercel breach explains how a small change in a trusted surface can ripple outward.
This article focuses on four implementation questions:
- How can compromised docs hurt API consumers?
- When is docs-as-code in Git safe enough?
- What does “secure API documentation” mean in practical terms?
- How can a managed documentation layer reduce the risk?
For related angles, see what the GitHub breach means for self-hosted API tools and VS Code extension API key security.
What goes wrong when your API docs repo or host is compromised
Start with the threat model.
Your API docs usually depend on three surfaces:
- The Git repo that stores the spec and markdown
- The CI/CD pipeline that builds the docs
- The host that serves the generated site
If any of those are compromised, several concrete failures can follow.
1. Documentation tampering reaches production code
This is the highest-impact case.
An attacker with write access to your docs repo or hosting layer makes a small edit:
- Changes
https://api.payments.acme.com/v2/chargeto a lookalike domain - Replaces an example bearer token with one that routes through their proxy
- Modifies the OAuth token exchange URL
- Alters a code sample to send secrets to an attacker-controlled endpoint
The docs still render. The YAML may still validate. CI may still pass.
Example OpenAPI fragment:
paths:
/v2/payment-intents:
post:
summary: Create a payment intent
servers:
- url: https://api.acme-pay.com
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentIntentRequest'
responses:
'201':
description: Payment intent created
A malicious change to servers.url is tiny:
- url: https://api.acme-pay.com
+ url: https://api-acme-pay.example.com
If consumers generate clients from the spec, they may start sending sensitive data to the wrong host.
Action item: add automated checks for trusted domains in your OpenAPI files.
Example script:
import fs from "node:fs";
import yaml from "yaml";
const file = fs.readFileSync("./openapi.yaml", "utf8");
const spec = yaml.parse(file);
const allowedHosts = new Set([
"api.acme-pay.com",
"sandbox.api.acme-pay.com",
]);
function checkServerUrl(url) {
const host = new URL(url).host;
if (!allowedHosts.has(host)) {
throw new Error(`Unexpected OpenAPI server host: ${host}`);
}
}
for (const server of spec.servers ?? []) {
checkServerUrl(server.url);
}
for (const pathItem of Object.values(spec.paths ?? {})) {
for (const operation of Object.values(pathItem ?? {})) {
for (const server of operation.servers ?? []) {
checkServerUrl(server.url);
}
}
}
console.log("OpenAPI server URLs passed validation.");
Run this in CI before publishing docs.
2. Internal and undocumented endpoints leak
Docs repos often accumulate internal details:
- Admin endpoints
- Debug routes
- Partner-only APIs
- Deprecated operations
- Internal schemas
- Example payloads with sensitive structure
If the repo is public, or becomes public through misconfiguration, that spec becomes an attacker’s map.
Even private repos are not immune. If a breach exfiltrates private repositories, the attacker gets endpoint paths, parameters, request bodies, response formats, and auth assumptions without scanning.
Action item: split public and internal specs.
For example:
/specs
public.openapi.yaml
partner.openapi.yaml
internal.openapi.yaml
Then enforce publication rules:
# Only publish the public spec to public docs
apidoc-build ./specs/public.openapi.yaml
Also add a CI check that blocks known internal paths from the public spec:
const blockedPathPatterns = [
/^\/admin/,
/^\/internal/,
/^\/debug/,
];
for (const path of Object.keys(spec.paths ?? {})) {
for (const pattern of blockedPathPatterns) {
if (pattern.test(path)) {
throw new Error(`Blocked internal path found in public spec: ${path}`);
}
}
}
For a broader review process, use an API security checklist like this API security testing checklist for 2026.
3. Public GitHub Pages has no access control
GitHub Pages is a static host. For fully public API docs, that is fine.
For private, partner-only, customer-only, or internal docs, it is usually not enough because it does not provide reader-level access control.
A hard-to-guess URL is not access control. URLs leak through:
- Browser history
- Referrer headers
- Proxy logs
- Shared bookmarks
- Screenshots
- Chat messages
Action item: classify each docs site.
Create a simple inventory:
| Docs site | Audience | Host | Access control | Owner |
|---|---|---|---|---|
| Public API docs | Everyone | GitHub Pages | None | DevRel |
| Partner API docs | Approved partners | Static host | None | Partnerships |
| Internal admin API docs | Engineering | Internal wiki | SSO | Platform |
If the audience is anything other than “everyone,” use real access control: password, SSO, IP allowlist, email allowlist, or a private network gate.
4. Stale docs become unverifiable docs
Not every failure requires an attacker.
A common docs failure looks like this:
- An engineer changes API behavior.
- The OpenAPI spec is not updated.
- Markdown examples remain stale.
- Consumers integrate against incorrect docs.
- Nobody knows whether the docs are old, wrong, or tampered with.
When documentation is stale, integrity checks get harder because the team loses confidence in the source of truth.
Action item: validate the spec against implementation or contract tests.
At minimum, add a CI step that checks whether the OpenAPI file is valid:
npx @redocly/cli lint openapi.yaml
Better: test real responses against the documented schema in your integration tests.
When docs-as-code in Git is fine, and when it is a liability
Docs-as-code is a good practice when implemented carefully.
Storing OpenAPI specs and markdown in Git gives you:
- Pull request review
- Change history
- Versioning alongside code
- Diff visibility
- Automated builds
Tools like Swagger UI and Redoc fit this workflow well.
The question is not “Git or not Git.” The question is whether your current docs pipeline matches the sensitivity of your API.
Docs-as-code in Git is fine when
Use Git-hosted docs when these conditions hold:
- The API is fully public.
- The repository has branch protection.
- Required reviews are enabled.
- Write access is limited and audited.
- CI/CD tokens are scoped.
- Third-party CI actions are pinned.
- Documentation changes receive the same review rigor as code.
- The spec is generated from or validated against the real API.
- Someone owns documentation freshness.
Example GitHub branch protection baseline:
main branch:
- Require pull request before merging
- Require approvals
- Dismiss stale approvals
- Require status checks
- Require signed commits where possible
- Restrict who can push
- Require conversation resolution
Example GitHub Actions hardening:
permissions:
contents: read
pages: write
id-token: write
jobs:
build-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint OpenAPI
run: npx @redocly/cli lint openapi.yaml
- name: Validate allowed server URLs
run: node scripts/check-openapi-hosts.js
Docs-as-code in Git becomes a liability when
The same setup becomes risky when:
- Docs should be private, but the host has no access control.
- “Private” means “unlinked.”
- Write access includes broad service accounts or unmanaged CI tokens.
- Docs PRs are rubber-stamped.
- The spec is hand-maintained and stale.
- Internal endpoints live beside public endpoints.
- Nobody can prove the deployed site matches the reviewed source.
- The deploy target can be modified outside the reviewed pipeline.
The GitHub breach maps directly to this risk model. If your internal API spec lives in a private repo and that repo is stolen, Git history does not preserve confidentiality. It only tells you what changed.
For a fuller comparison of hosting patterns, see this self-hosted API docs comparison.
What “secure API documentation” means in practice
Treat secure API documentation as a checklist with four properties.
1. Access control
Docs should be visible only to the intended audience.
Use:
- Public access for public APIs
- Password protection for lightweight restricted sharing
- Email allowlists for customer or partner docs
- IP allowlists for internal docs
- SSO or custom auth for enterprise access
Test:
Can you name exactly who can read your docs right now, and can you revoke one of them quickly?
2. Versioning
Every published API version should have matching docs.
Good versioning prevents this failure:
Consumer uses API v1
Docs silently update to v2
Consumer implements the wrong behavior
Use URLs or selectors like:
/docs/v1
/docs/v2
/docs/latest
Test:
Can a developer integrating with an older API version still find accurate docs for that version?
3. Integrity
You need confidence that published docs match what you intended to publish.
Implementation options:
- Generate docs from a controlled source of truth.
- Require PR review for all docs changes.
- Validate OpenAPI files in CI.
- Restrict deploy permissions.
- Compare published output with reviewed source.
Test:
If someone changed one endpoint URL on the live docs an hour ago, would anything alert you?
4. Audit trail
You need to answer:
- Who changed the docs?
- What changed?
- When did it change?
- Who approved it?
- What version was published?
Git gives you part of this for the repository. You also need auditability for the published surface and deployment path.
Test:
Can you produce a change log for your published docs over the last 90 days?
How Apidog gives you secure API documentation
Apidog is an all-in-one API platform for designing, debugging, testing, mocking, and documenting APIs. Its documentation workflow is built around the four properties above: access control, versioning, integrity, and auditability.
To try the workflow, download Apidog and open a project with an API definition.
1. Publish docs from a controlled source of truth
In Apidog, documentation is generated from the API design inside the project. You define endpoints, schemas, auth, and examples in the visual designer, and Apidog auto-generates the documentation from that definition.
Typical flow:
- Import or create an API definition.
- Define endpoints, schemas, and auth.
- Review the generated documentation.
- Publish an interactive docs site.
- Share it with the intended audience.
The integrity benefit is structural: the published docs are not a separate markdown site that can drift independently. They reflect the API definition managed in the project.
2. Add documentation access control
When publishing docs in Apidog, choose the appropriate visibility mode:
- Public: anyone with the link can read it.
- Password protection: readers must enter a password.
- IP allowlist: restrict access to specific IPs or ranges.
- Email allowlist: allow specific email addresses or domains.
- Custom login: connect your own auth system using JWT-based access.
For example:
| Docs type | Recommended access control |
|---|---|
| Public developer API | Public |
| Beta API docs | Password or email allowlist |
| Partner API docs | Email allowlist |
| Internal API docs | IP allowlist or custom login |
| Enterprise customer docs | Custom login |
Apidog documents these methods in its guide to controlling API documentation access.
3. Use a custom domain
You can publish docs under your own domain, such as:
developer.yourcompany.com
Apidog supports a custom domain through a DNS CNAME or reverse proxy.
A custom domain is not access control by itself, but it helps centralize ownership and governance. Consumers also get a recognizable domain instead of a generic docs URL.
4. Keep the OpenAPI spec in sync with API design
Documentation drift is a security and reliability problem. If the docs are stale, consumers cannot tell whether an error is caused by bad docs, old docs, or tampered docs.
Apidog treats API design as the source of truth and keeps documentation aligned with that design. It also imports OpenAPI 3.0, OpenAPI 3.1, and Swagger 2.0, and supports scheduled imports so an external spec can stay current automatically.
If you currently maintain specs by hand in Git, consider this migration path:
- Import the OpenAPI file into Apidog.
- Review endpoints, schemas, and auth settings.
- Publish the generated docs.
- Compare the published docs with the previous docs site.
- Move future changes into the controlled API design workflow.
Teams coming from SwaggerHub can use this guide to migrating SwaggerHub API docs to Apidog.
5. Publish multiple documentation versions
Apidog supports documentation versioning, so you can keep multiple versions available side by side.
Example:
v1 docs -> stable customers
v2 docs -> new integrations
beta docs -> early-access partners
This helps consumers integrate against the correct contract and gives your team a clearer history of how the API changed over time.
Comparing documentation hosting options
Use the following table to evaluate your current setup.
| Property | Public GitHub Pages (Swagger UI / Redoc) | Self-hosted docs on your own server | Managed docs (Apidog) |
|---|---|---|---|
| Access control | None; URL obscurity only | Whatever you build and maintain | Built in: password, IP, email, custom login |
| Versioning | Manual; separate builds or branches | Manual | Built in; versions published side by side |
| Integrity | Git review + history, if enforced | Depends on your pipeline | Docs generated from controlled API design |
| Audit trail | Git history for repo, not always for deploy | Depends on your logging | Change history on design and published docs |
| Maintenance cost | Low to set up, ongoing pipeline upkeep | High; you own the whole stack | Low; platform handles hosting and gates |
| Best fit | Fully public APIs with disciplined pipelines | Teams with strict self-hosting needs | Teams needing access control without ops overhead |
There is no universally correct option.
Use GitHub Pages when your API is public and your pipeline is locked down. Use self-hosting when you have strict residency, isolation, or platform requirements. Use managed docs when you need access control, versioning, and lower operational overhead.
For more tradeoffs, see the self-hosted API docs comparison and the Scalar vs SwaggerHub vs Apidog comparison.
Practical audit checklist
Use this checklist against every API docs site you publish.
Inventory
[ ] Do we know every place our API docs are published?
[ ] Does each docs site have an owner?
[ ] Is each docs site classified as public, partner, customer, or internal?
Access control
[ ] Are non-public docs protected by a real gate?
[ ] Can we revoke access quickly?
[ ] Are shared passwords rotated?
[ ] Are IP or email allowlists reviewed?
Versioning
[ ] Are docs available for every supported API version?
[ ] Are deprecated versions clearly marked?
[ ] Can consumers find the correct version without guessing?
Integrity
[ ] Are OpenAPI specs linted in CI?
[ ] Are server URLs validated?
[ ] Are internal paths blocked from public specs?
[ ] Are docs generated from a controlled source of truth?
[ ] Can we prove the live docs match reviewed source?
Audit trail
[ ] Can we see who changed the docs?
[ ] Can we see who approved the change?
[ ] Can we see when docs were published?
[ ] Can we produce a 90-day change log?
Pipeline security
[ ] Are deploy credentials scoped?
[ ] Are CI actions pinned?
[ ] Are service accounts reviewed?
[ ] Are branch protections enabled?
Conclusion
The GitHub breach is not a reason to abandon docs-as-code or distrust GitHub. It is a reason to audit a surface many teams ignore: API documentation.
Start with a simple inventory. List every place your docs are published, classify the audience, and check each site against four properties:
- Access control
- Versioning
- Integrity
- Audit trail
If the widest gap is access control, publish one project’s docs with a password or email allowlist in Apidog and compare that workflow with your current static docs setup.

Top comments (0)