Add NFC normalization to all FormData inputs across 41 server actions
Local Build and Deploy / deploy (push) Successful in 59s
Local Build and Deploy / deploy (push) Successful in 59s
All user-supplied string values from FormData now go through
String.prototype.normalize('NFC') to prevent Unicode homoglyph
attacks and canonicalization bypasses. NFC is idempotent for
already-normalized strings, so this is a pure security improvement
with zero behavioral change for legitimate users.
This commit is contained in:
1 parent
e2fc7ea1a4
commit
e5ae51bff7
41 files changed
+152
-152
No files matched your search
@@ -30,24 +30,24 @@ export async function saveTheme(formData: FormData): Promise<void> {
|
||||
for (const mode of ["light", "dark"] as const) {
|
||||
for (const key of THEME_COLOR_KEYS) {
|
||||
const dbKey = settingKey(key, mode);
|
||||
const raw = String(formData.get(dbKey) ?? "").trim();
|
||||
const raw = String(formData.get(dbKey) ?? "").normalize("NFC").trim();
|
||||
if (raw && COLOR_RE.test(raw)) await writeSetting(dbKey, raw);
|
||||
}
|
||||
}
|
||||
const radius = String(formData.get("border_radius") ?? "").trim();
|
||||
const radius = String(formData.get("border_radius") ?? "").normalize("NFC").trim();
|
||||
if (/^\d{1,3}$/.test(radius)) await writeSetting("border_radius", radius);
|
||||
|
||||
// Typography
|
||||
const font = String(formData.get("font_family") ?? "").trim();
|
||||
const font = String(formData.get("font_family") ?? "").normalize("NFC").trim();
|
||||
if (font in FONTS) await writeSetting("font_family", font);
|
||||
for (const key of HEADING_KEYS) {
|
||||
const v = String(formData.get(key) ?? "").trim();
|
||||
const v = String(formData.get(key) ?? "").normalize("NFC").trim();
|
||||
if (/^\d{1,3}$/.test(v)) await writeSetting(key, v);
|
||||
}
|
||||
|
||||
// Raw custom CSS (staff-trusted; length-capped, ThemeVars injects it as-is).
|
||||
if (formData.has("custom_css")) {
|
||||
const cssRaw = String(formData.get("custom_css") ?? "").slice(0, CUSTOM_CSS_MAX);
|
||||
const cssRaw = String(formData.get("custom_css") ?? "").normalize("NFC").slice(0, CUSTOM_CSS_MAX);
|
||||
await writeSetting("custom_css", cssRaw);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export async function saveTheme(formData: FormData): Promise<void> {
|
||||
|
||||
export async function applyPreset(formData: FormData): Promise<void> {
|
||||
const staff = await requireStaff();
|
||||
const name = String(formData.get("preset") ?? "");
|
||||
const name = String(formData.get("preset") ?? "").normalize("NFC");
|
||||
// eslint-disable-next-line security/detect-object-injection -- guarded by null check below
|
||||
const preset = PRESETS[name];
|
||||
if (!preset) redirect("/admin/theme");
|
||||
|
||||
Reference in new issue
Block a user