chore: improve sanitize function to catch escaped characters

This commit is contained in:
Nicolas Meienberger 2026-04-25 09:30:11 +02:00
parent f078e006c1
commit 7b3b7583c0
No known key found for this signature in database
3 changed files with 76 additions and 2 deletions

View file

@ -65,7 +65,7 @@ const mount = async (config: BackendConfig, path: string) => {
const args = ["-t", "cifs", "-o", options.join(","), source, path];
logger.debug(`Mounting SMB volume ${path}...`);
logger.info(`Executing mount: mount ${args.join(" ")}`);
logger.info(`Executing SMB mount for ${source} at ${path}`);
try {
await executeMount(args);

View file

@ -0,0 +1,74 @@
import { describe, expect, test } from "vitest";
import { sanitizeSensitiveData } from "../sanitize";
const withNodeEnv = (nodeEnv: string, fn: () => void) => {
const originalNodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = nodeEnv;
try {
fn();
} finally {
process.env.NODE_ENV = originalNodeEnv;
}
};
describe("sanitizeSensitiveData", () => {
test("redacts escaped comma password values", () => {
withNodeEnv("production", () => {
const sanitized = sanitizeSensitiveData(
"mount -t cifs -o username=user,password=abc\\,LEAKED_SUFFIX //server/share /mnt",
);
expect(sanitized).toBe("mount -t cifs -o username=user,password=*** //server/share /mnt");
expect(sanitized).not.toContain("LEAKED_SUFFIX");
});
});
test.each([
{
name: "password key",
input: "mount -o username=user,password=plainsecret //server/share /mnt",
expected: "mount -o username=user,password=*** //server/share /mnt",
secret: "plainsecret",
},
{
name: "pass key",
input: "backend returned pass=hunter2 while mounting",
expected: "backend returned pass=*** while mounting",
secret: "hunter2",
},
{
name: "uppercase key",
input: "mount -o PASSWORD=CaseSecret //server/share /mnt",
expected: "mount -o PASSWORD=*** //server/share /mnt",
secret: "CaseSecret",
},
{
name: "URL basic auth",
input: "request failed for https://alice:supersecret@example.com/hook",
expected: "request failed for https://alice:***@example.com/hook",
secret: "supersecret",
},
{
name: "space-delimited URL credential entry",
input: "https://dav.example.test/path operator dav-password",
expected: "https://dav.example.test/path operator ***",
secret: "dav-password",
},
])("redacts $name", ({ input, expected, secret }) => {
withNodeEnv("production", () => {
const sanitized = sanitizeSensitiveData(input);
expect(sanitized).toBe(expected);
expect(sanitized).not.toContain(secret);
});
});
test("does not redact in development", () => {
withNodeEnv("development", () => {
const input = "mount -o username=user,password=devsecret //server/share /mnt";
expect(sanitizeSensitiveData(input)).toBe(input);
});
});
});

View file

@ -7,7 +7,7 @@ export const sanitizeSensitiveData = (text: string): string => {
return text;
}
let sanitized = text.replace(/\b(pass|password)=([^\s,]+)/gi, "$1=***");
let sanitized = text.replace(/\b(pass|password)=((?:\\.|[^\s,])*)/gi, "$1=***");
sanitized = sanitized.replace(/\/\/([^:@\s]+):([^@\s]+)@/g, "//$1:***@");