Skip to content

Commit 2ae0bdd

Browse files
committed
Fix CodeQL findings: string escaping and path traversal
- generate-markdown.mjs: escape backslashes in YAML title (incomplete string escaping) - serve-content-negotiation-local-test.mjs: resolve and validate path stays within ROOT
1 parent 345bfd1 commit 2ae0bdd

2 files changed

Lines changed: 11 additions & 3 deletions

File tree

scripts/generate-markdown.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ function extractTitle(doc) {
4444
function buildFrontmatter(title, tokens) {
4545
return [
4646
'---',
47-
`title: "${title.replace(/"/g, '\\"')}"`,
47+
`title: "${title.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`,
4848
`tokens: ${tokens}`,
4949
'---',
5050
'',

scripts/serve-content-negotiation-local-test.mjs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313

1414
import { createReadStream } from 'node:fs';
1515
import { readFile, stat } from 'node:fs/promises';
16-
import { join, extname } from 'node:path';
16+
import { join, extname, resolve, sep } from 'node:path';
1717
import { createServer } from 'node:http';
1818

1919
const PORT = Number(process.argv[2]) || 4000;
2020
const BUILD_DIR = process.argv[3] || 'build/site';
21+
const ROOT = resolve(BUILD_DIR);
2122

2223
// ---------------------------------------------------------------------------
2324
// Load manifest (token counts per URL path)
@@ -73,7 +74,14 @@ async function handler(req, res) {
7374
if (urlPath.endsWith('/')) urlPath += 'index.html';
7475
if (!extname(urlPath)) urlPath += '/index.html';
7576

76-
const htmlFile = join(BUILD_DIR, urlPath);
77+
// Normalize and constrain path to ROOT to prevent traversal
78+
const relativePath = urlPath.replace(/^\/+/, '');
79+
const htmlFile = resolve(ROOT, relativePath);
80+
if (!(htmlFile === ROOT || htmlFile.startsWith(ROOT + sep))) {
81+
res.writeHead(403, { 'Content-Type': 'text/plain' });
82+
res.end('403 Forbidden');
83+
return;
84+
}
7785

7886
// Content negotiation: swap .html → .md when agent requests markdown
7987
if (wantsMarkdown(req) && urlPath.endsWith('.html')) {

0 commit comments

Comments
 (0)