-
Notifications
You must be signed in to change notification settings - Fork 5
Markdown content negotiation #1267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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 Agent can help with this pull request. Just |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| source = fs.readFileSync(candidatePath); | ||
| sourcePath = candidatePath; | ||
| break; | ||
| } |
There was a problem hiding this comment.
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.
| pathname.startsWith("/api/") || | ||
| pathname.startsWith("/_next/") || | ||
| pathname.startsWith("/images/") || | ||
| pathname.includes(".") // Skip files with extensions (e.g., .png, .js, .css) |
There was a problem hiding this comment.
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.
Description
This PR adds a feature to serve raw markdown content for docs pages when requested with an
Accept: text/markdownheader.Why: This allows clients to programmatically fetch the source markdown of any documentation page, enabling use cases like embedding or custom rendering.
How:
middleware.tsintercepts requests and checks forAccept: text/markdownorAccept: text/x-markdownheaders. If present, it rewrites the request to 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 aContent-Type: text/markdown; charset=utf-8header.req.query.Todos
Tasks
Screenshots