fix(app): block sensitive file reads in filesystem API

Add SENSITIVE_PATTERNS denylist to handleRead() in vite-fs.ts.
Blocks access to .env*, .git/, credentials, secrets, .pem, .key,
and SSH key files. Returns 403 for matched paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-06 01:26:01 +00:00
co-authored by Claude Opus 4.6
parent 4dc9588c8a
commit c21939b1f8
+27 -1
View File
@@ -1,7 +1,7 @@
import type { Plugin } from 'vite'
import type { Connect } from 'vite'
import { readdirSync, statSync, readFileSync, existsSync, mkdirSync } from 'fs'
import { join, resolve, relative } from 'path'
import { join, resolve, relative, basename } from 'path'
import { validateDevAuth } from './server/dev-auth'
const PROJECTS_ROOT = '/Users/dorian/Projects'
@@ -123,6 +123,26 @@ function handleTree(req: Connect.IncomingMessage, res: any) {
}
}
/** Patterns that indicate sensitive files — block reads */
const SENSITIVE_PATTERNS = [
/^\.env/i,
/^\.git$/,
/^\.git\//,
/credentials/i,
/secret/i,
/\.pem$/i,
/\.key$/i,
/id_rsa/i,
/id_ed25519/i,
]
function isSensitivePath(filePath: string): boolean {
const resolved = resolve(filePath)
const relToRoot = relative(PROJECTS_ROOT, resolved)
const segments = relToRoot.split('/')
return segments.some(seg => SENSITIVE_PATTERNS.some(p => p.test(seg)))
}
/** GET /api/fs/read — read file content */
function handleRead(req: Connect.IncomingMessage, res: any) {
const url = parseUrl(req)
@@ -133,6 +153,12 @@ function handleRead(req: Connect.IncomingMessage, res: any) {
return
}
if (isSensitivePath(filePath)) {
res.writeHead(403, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({ error: 'Access denied: sensitive file' }))
return
}
try {
const stat = statSync(filePath)
if (stat.isDirectory()) {