fix: redact S3 credentials in backup logs regardless of shell quoting

This commit is contained in:
Souvik Kumar
2026-09-27 00:23:23 +05:30
parent a0e0574bcd
commit 6215c7f159
2 changed files with 62 additions and 3 deletions
@@ -1,4 +1,6 @@
import type { Destination } from "@dokploy/server/services/destination";
import { redactRcloneCredentials } from "@dokploy/server/utils/backups/redact";
import { getS3Credentials } from "@dokploy/server/utils/backups/utils";
import { describe, expect, it } from "vitest";
describe("redactRcloneCredentials (#4621)", () => {
@@ -48,3 +50,48 @@ describe("redactRcloneCredentials (#4621)", () => {
expect(redacted).toContain("[REDACTED]");
});
});
describe("redactRcloneCredentials with getS3Credentials output (#5519)", () => {
const buildCommand = (accessKey: string, secretAccessKey: string) =>
`rclone rcat ${getS3Credentials({
accessKey,
secretAccessKey,
region: "us-west-001",
endpoint: "https://s3.us-west-001.backblazeb2.com",
provider: "Other",
} as Destination).join(" ")} :s3:bucket/file.gz`;
it.each([
[
"plain alphanumeric",
"001aaaabbbbccccdd0000000001",
"K001FAKEfakeFAKEfake",
],
[
"containing slashes",
"AKIAIOSFODNN7EXAMPLE",
"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
],
["containing spaces", "key with space", "secret with space"],
["containing quotes", "it's-a-key", `say "hi" it's`],
["containing shell metacharacters", "key$HOME", "sec;ret`id`&|\\x"],
])("redacts credentials %s", (_, accessKey, secretAccessKey) => {
const redacted = redactRcloneCredentials(
buildCommand(accessKey, secretAccessKey),
);
expect(redacted).toContain(
'--s3-access-key-id="[REDACTED]" --s3-secret-access-key="[REDACTED]" --s3-region=us-west-001',
);
expect(redacted).not.toContain(accessKey);
expect(redacted).not.toContain(secretAccessKey);
expect(redacted).toContain(":s3:bucket/file.gz");
});
it("redacts credentials embedded in an error string", () => {
const errorStr = `Error: Command failed: ${buildCommand("MYKEY", "MY/SECRET")}`;
const redacted = redactRcloneCredentials(errorStr);
expect(redacted).not.toContain("MYKEY");
expect(redacted).not.toContain("MY/SECRET");
expect(redacted).toContain("[REDACTED]");
});
});
+15 -3
View File
@@ -1,12 +1,24 @@
// A shell word as produced by shell-quote: bare, 'single' or "double" quoted.
const SHELL_WORD = String.raw`(?:[^\s'"\\]|\\.|'[^']*'|"(?:[^"\\]|\\.)*")+`;
const ACCESS_KEY_PATTERN = new RegExp(
`(--s3-access-key-id=)${SHELL_WORD}`,
"g",
);
const SECRET_KEY_PATTERN = new RegExp(
`(--s3-secret-access-key=)${SHELL_WORD}`,
"g",
);
/**
* Redacts S3 credentials from rclone command strings.
*
* Used to prevent credential leakage in structured logs and error output.
* Matches the flag format produced by `getS3Credentials()`:
* --s3-access-key-id="VALUE" and --s3-secret-access-key="VALUE"
* --s3-access-key-id=VALUE and --s3-secret-access-key=VALUE (shell-quoted)
*/
export const redactRcloneCredentials = (command: string): string => {
return command
.replace(/(--s3-access-key-id=)"[^"]*"/g, '$1"[REDACTED]"')
.replace(/(--s3-secret-access-key=)"[^"]*"/g, '$1"[REDACTED]"');
.replace(ACCESS_KEY_PATTERN, '$1"[REDACTED]"')
.replace(SECRET_KEY_PATTERN, '$1"[REDACTED]"');
};