diff --git a/server/validation.test.ts b/server/validation.test.ts index 2430a9094c..759ee6fab0 100644 --- a/server/validation.test.ts +++ b/server/validation.test.ts @@ -48,4 +48,12 @@ describe("#ValidateKey.sanitize", () => { ValidateKey.sanitize(`public/${uuid1}/${uuid2}/~\.\u0000\malicious_key`) ).toEqual(`public/${uuid1}/${uuid2}/~.malicious_key`); }); + + it("should remove potential path traversal", () => { + const uuid1 = uuidv4(); + const uuid2 = uuidv4(); + expect( + ValidateKey.sanitize(`public/${uuid1}/${uuid2}/../../malicious_key`) + ).toEqual(`public/${uuid1}/${uuid2}/malicious_key`); + }); }); diff --git a/server/validation.ts b/server/validation.ts index eaf36fd800..d547a2d64f 100644 --- a/server/validation.ts +++ b/server/validation.ts @@ -174,6 +174,13 @@ export const assertCollectionPermission = ( }; export class ValidateKey { + /** + * Checks if key is valid. A valid key is of the form + * /// + * + * @param key + * @returns true if key is valid, false otherwise + */ public static isValid = (key: string) => { let parts = key.split("/"); const bucket = parts[0]; @@ -189,11 +196,18 @@ export class ValidateKey { ); }; + /** + * Sanitizes a key by removing any invalid characters + * + * @param key + * @returns sanitized key + */ public static sanitize = (key: string) => { const [filename] = key.split("/").slice(-1); return key .split("/") .slice(0, -1) + .filter((part) => part !== "" && part !== ".." && part !== ".") .join("/") .concat(`/${sanitize(filename)}`); };