fix(security): re-auth on DB export/import + SSRF guard on web fetch

- /api/settings/database now requires current password (header for GET,
  body for POST) in addition to session; CLI-token requests exempt
- add verifyDashboardPassword helper reusing login bcrypt check
- profile UI prompts password via modal before export/import
- /v1/web/fetch rejects internal/private/metadata targets via assertPublicUrl

Refs GHSA-qvfm-67h2-2qfx, GHSA-qj3v-64wj-q825

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
decolua
2026-06-13 11:40:35 +07:00
co-authored by Cursor
parent e6bac77696
commit 0c7c9de00a
5 changed files with 150 additions and 13 deletions
+14
View File
@@ -1,8 +1,12 @@
import { SignJWT, jwtVerify } from "jose";
import bcrypt from "bcryptjs";
import fs from "node:fs";
import path from "node:path";
import crypto from "node:crypto";
import { DATA_DIR } from "@/lib/dataDir";
import { getSettings } from "@/lib/localDb";
const DEFAULT_PASSWORD = "123456";
function loadJwtSecret() {
if (process.env.JWT_SECRET) return process.env.JWT_SECRET;
@@ -66,3 +70,13 @@ export async function setDashboardAuthCookie(cookieStore, request, claims = {})
export function clearDashboardAuthCookie(cookieStore) {
cookieStore.delete("auth_token");
}
// Verify the current dashboard password (re-auth for sensitive actions).
export async function verifyDashboardPassword(password) {
if (typeof password !== "string" || !password) return false;
const settings = await getSettings();
const storedHash = settings?.password;
if (storedHash) return bcrypt.compare(password, storedHash);
const initialPassword = process.env.INITIAL_PASSWORD || DEFAULT_PASSWORD;
return password === initialPassword;
}