Sanitize Upload Filenames
Make untrusted upload names safe by stripping paths, control characters, reserved names and dangerous extensions.
Code
const RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\..*)?$/i;
export interface SanitizeOptions {
maxLength?: number;
replacement?: string;
fallback?: string;
}
export function sanitizeFilename(input: string, options: SanitizeOptions = {}): string {
const { maxLength = 120, replacement = "_", fallback = "file" } = options;
if (!Number.isInteger(maxLength) || maxLength < 1) {
throw new RangeError("maxLength must be a positive integer");
}
if (!replacement || /[\\/:*?"<>|]/.test(replacement)) {
throw new TypeError("replacement contains forbidden characters");
}
const normalized = String(input).normalize("NFC").replace(/[\u0000-\u001f\u007f]/g, "");
const base = normalized.split(/[\\/]/).pop() ?? "";
let name = base
.replace(/[<>:"|?*]/g, replacement)
.replace(/\s+/g, " ")
.trim()
.replace(/^\.+/, "")
.replace(/\.+$/, "");
if (!name) return fallback;
const dot = name.lastIndexOf(".");
const extension = dot > 0 ? name.slice(dot).slice(0, 16) : "";
let stem = dot > 0 ? name.slice(0, dot) : name;
if (RESERVED_NAMES.test(stem)) stem = "_" + stem;
const budget = Math.max(1, maxLength - extension.length);
stem = stem.slice(0, budget).trim();
if (!stem) stem = fallback;
name = stem + extension;
return name;
}Report a problem with this exampleOpens a pre-filled issue on GitHub.