Skip to content

Commit 6939484

Browse files
authored
Merge pull request #190 from ucdavis/codeql/2-security-alerts
CodeQL 2: fix(security): close remaining CodeQL security alerts
2 parents 987d173 + a6ad40f commit 6939484

4 files changed

Lines changed: 31 additions & 41 deletions

File tree

scripts/lib/lint-staged-common.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ function sanitizeFilePath(filePath, baseDir, allowedExtensions, maxFileSizeMB =
318318

319319
// On Windows, lint-staged may pass paths like C:/path/to/file
320320
// Convert these to proper Windows format first
321-
if (IS_WINDOWS && /^[A-Za-z]:[\\\\/]/.test(filePath)) {
321+
if (IS_WINDOWS && /^[A-Za-z]:[\\/]/.test(filePath)) {
322322
normalizedPath = filePath.replaceAll("/", path.sep)
323323
}
324324

scripts/lint-any.js

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -304,24 +304,32 @@ function runOxfmtCheck(files, fix) {
304304
* @param {string[]} files - Array of file paths
305305
* @param {boolean} fix - Whether to pass --fix
306306
* @param {boolean} clearCache - Whether to pass --clear-cache
307-
* @returns {{ scriptArgs: string[], tempFile: string | null }}
307+
* @returns {{ scriptArgs: string[], cleanup: (() => void) | null }}
308308
*/
309309
function buildScriptArgs(files, fix, clearCache) {
310310
const scriptArgs = []
311-
let tempFile = null
311+
let cleanup = null
312312

313313
const totalLength = files.reduce((sum, f) => sum + f.length + 1, 0)
314314
if (totalLength > MAX_ARG_LENGTH) {
315-
const RADIX = 36
316-
const SUFFIX_LENGTH = 8
317-
tempFile = path.join(
318-
os.tmpdir(),
319-
`lint-files-${Date.now()}-${Math.random()
320-
.toString(RADIX)
321-
.slice(2, 2 + SUFFIX_LENGTH)}.txt`,
322-
)
323-
fs.writeFileSync(tempFile, files.join("\n"), "utf8")
324-
scriptArgs.push(`--files-from=${tempFile}`)
315+
// Use mkdtempSync (private mode-0700 dir with cryptographic suffix) so the
316+
// inner file cannot be predicted/preempted by another local process.
317+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "lint-files-"))
318+
const tempFile = path.join(tempDir, "files.txt")
319+
cleanup = () => {
320+
try {
321+
fs.rmSync(tempDir, { recursive: true, force: true })
322+
} catch {
323+
/* Best-effort cleanup */
324+
}
325+
}
326+
try {
327+
fs.writeFileSync(tempFile, files.join("\n"), "utf8")
328+
scriptArgs.push(`--files-from=${tempFile}`)
329+
} catch (error) {
330+
cleanup()
331+
throw error
332+
}
325333
} else {
326334
scriptArgs.push(...files)
327335
}
@@ -333,7 +341,7 @@ function buildScriptArgs(files, fix, clearCache) {
333341
scriptArgs.push("--clear-cache")
334342
}
335343

336-
return { scriptArgs, tempFile }
344+
return { scriptArgs, cleanup }
337345
}
338346

339347
/**
@@ -352,21 +360,15 @@ function runLinter(script, files, description, fix, clearCache) {
352360
console.log(`\n🔍 ${description} (${files.length} files)`)
353361

354362
const scriptPath = path.join(__dirname, script)
355-
const { scriptArgs, tempFile } = buildScriptArgs(files, fix, clearCache)
363+
const { scriptArgs, cleanup } = buildScriptArgs(files, fix, clearCache)
356364

357365
const result = spawnSync("node", [scriptPath, ...scriptArgs], {
358366
stdio: "inherit",
359367
cwd: projectRoot,
360368
env,
361369
})
362370

363-
if (tempFile) {
364-
try {
365-
fs.unlinkSync(tempFile)
366-
} catch {
367-
/* Best-effort cleanup */
368-
}
369-
}
371+
cleanup?.()
370372

371373
if (result.error) {
372374
console.error(`❌ Failed to run ${script}:`, result.error.message)
@@ -392,7 +394,7 @@ function runLinterAsync(script, files, description, fix, clearCache) {
392394
console.log(`\n🔍 ${description} (${files.length} files)`)
393395

394396
const scriptPath = path.join(__dirname, script)
395-
const { scriptArgs, tempFile } = buildScriptArgs(files, fix, clearCache)
397+
const { scriptArgs, cleanup } = buildScriptArgs(files, fix, clearCache)
396398

397399
return new Promise((resolve) => {
398400
const child = spawn("node", [scriptPath, ...scriptArgs], {
@@ -402,13 +404,7 @@ function runLinterAsync(script, files, description, fix, clearCache) {
402404
})
403405

404406
child.on("close", (code, signal) => {
405-
if (tempFile) {
406-
try {
407-
fs.unlinkSync(tempFile)
408-
} catch {
409-
/* Best-effort cleanup */
410-
}
411-
}
407+
cleanup?.()
412408
if (signal) {
413409
console.error(`❌ ${script} terminated by signal ${signal}`)
414410
resolve(1)
@@ -417,13 +413,7 @@ function runLinterAsync(script, files, description, fix, clearCache) {
417413
resolve(code ?? 1)
418414
})
419415
child.on("error", (err) => {
420-
if (tempFile) {
421-
try {
422-
fs.unlinkSync(tempFile)
423-
} catch {
424-
/* Best-effort cleanup */
425-
}
426-
}
416+
cleanup?.()
427417
console.error(`❌ Failed to run ${script}:`, err.message)
428418
resolve(1)
429419
})

web/Program.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
// Load .env.local for local development only (multiple-instance support)
3232
// Avoid loading in production - guard by ASPNETCORE_ENVIRONMENT.
33-
var envPath = Path.Combine(Directory.GetCurrentDirectory(), "../.env.local");
33+
var envPath = Path.Join(Directory.GetCurrentDirectory(), "../.env.local");
3434
var aspNetEnv = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
3535
if (string.Equals(aspNetEnv, "Development", StringComparison.OrdinalIgnoreCase)
3636
&& File.Exists(envPath))
@@ -476,7 +476,7 @@ void RegisterDbContext<TContext>(string connectionStringKey) where TContext : Db
476476
{
477477
DefaultFileNames = new List<string> { "index.html" },
478478
FileProvider = new PhysicalFileProvider(
479-
Path.Combine(builder.Environment.ContentRootPath, "wwwroot/vue")),
479+
Path.Join(builder.Environment.ContentRootPath, "wwwroot/vue")),
480480
RequestPath = "/vue",
481481
RedirectToAppendTrailingSlash = true
482482
});
@@ -487,7 +487,7 @@ void RegisterDbContext<TContext>(string connectionStringKey) where TContext : Db
487487
app.UseStaticFiles(new StaticFileOptions
488488
{
489489
FileProvider = new PhysicalFileProvider(
490-
Path.Combine(builder.Environment.ContentRootPath, "wwwroot/vue")),
490+
Path.Join(builder.Environment.ContentRootPath, "wwwroot/vue")),
491491
RequestPath = "/2/vue"
492492
});
493493

web/ViteProxyHelpers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ public static async Task HandleProxyError(HttpContext context, Exception ex, ILo
339339
}
340340
}
341341

342-
var physicalPath = Path.Combine(context.RequestServices.GetRequiredService<IWebHostEnvironment>().WebRootPath,
342+
var physicalPath = Path.Join(context.RequestServices.GetRequiredService<IWebHostEnvironment>().WebRootPath,
343343
staticPath.TrimStart('/').Replace('/', Path.DirectorySeparatorChar));
344344

345345
// Prevent directory traversal: ensure the resolved physical path is within WebRootPath

0 commit comments

Comments
 (0)