Skip to content

Conversation

@cjbell
Copy link
Contributor

@cjbell cjbell commented Jan 15, 2026

Description

This PR adds a feature to serve raw markdown content for docs pages when requested with an Accept: text/markdown header.

Why: This allows clients to programmatically fetch the source markdown of any documentation page, enabling use cases like embedding or custom rendering.

How:

  • A new middleware.ts intercepts requests and checks for Accept: text/markdown or Accept: text/x-markdown headers. If present, it rewrites the request to a new API route.
  • A new API route, /pages/api/markdown/[...slug].ts, reads the corresponding MDX/MD file from the content directory and returns its raw content with a Content-Type: text/markdown; charset=utf-8 header.
  • The API route correctly parses the slug from the URL path, handling cases where middleware rewrites might not populate req.query.

Todos

Tasks

Screenshots


Open in Cursor Open in Web

cursoragent and others added 2 commits January 15, 2026 03:56
When a request includes Accept: text/markdown header, return the raw
markdown content instead of the rendered HTML page.

- Add middleware.ts to intercept requests with Accept: text/markdown
- Add /api/markdown/[...slug] API route to serve raw markdown content
- Support both text/markdown and text/x-markdown MIME types
- Skip API routes, static files, and special paths in middleware

Co-authored-by: chris <chris@knock.app>
When the middleware rewrites requests to the markdown API route,
the slug parameter isn't automatically populated in req.query.
This fix parses the slug directly from the URL path when needed.

Co-authored-by: chris <chris@knock.app>
@cursor
Copy link

cursor bot commented Jan 15, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@vercel
Copy link

vercel bot commented Jan 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
docs Ready Ready Preview, Comment Jan 15, 2026 4:16am

source = fs.readFileSync(candidatePath);
sourcePath = candidatePath;
break;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path traversal allows reading arbitrary files

High Severity

The API endpoint uses user-provided slug segments to construct a file path via path.join() without validating that the resolved path stays within CONTENT_DIR. Since path.join() resolves .. components, an attacker could request paths like /api/markdown/../../etc/passwd to read arbitrary files outside the content directory. The API route can be called directly, bypassing middleware protections.

Fix in Cursor Fix in Web

pathname.startsWith("/api/") ||
pathname.startsWith("/_next/") ||
pathname.startsWith("/images/") ||
pathname.includes(".") // Skip files with extensions (e.g., .png, .js, .css)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dot check blocks valid paths with periods

Medium Severity

The check pathname.includes(".") is intended to skip files with extensions like .png or .css, but it's too broad. It blocks any path containing a period anywhere, including legitimate documentation paths with version numbers like /docs/v1.2/intro or /docs/node.js/setup. These paths would incorrectly skip markdown serving.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants