diff --git a/libs/importer/spec/base-importer.spec.ts b/libs/importer/spec/base-importer.spec.ts index d21764a0c16..f72ceccb538 100644 --- a/libs/importer/spec/base-importer.spec.ts +++ b/libs/importer/spec/base-importer.spec.ts @@ -12,6 +12,10 @@ class FakeBaseImporter extends BaseImporter { setCardExpiration(cipher: CipherView, expiration: string): boolean { return super.setCardExpiration(cipher, expiration); } + + parseXml(data: string): Document { + return super.parseXml(data); + } } describe("BaseImporter class", () => { @@ -103,5 +107,18 @@ describe("BaseImporter class", () => { expect(result).toBe(false); }, ); + + it("parse XML should reject xml with external entities", async () => { + const xml = ` + + + ]> + + PoC XXE&xxe; + `; + const result = importer.parseXml(xml); + expect(result).toBe(null); + }); }); }); diff --git a/libs/importer/src/importers/base-importer.ts b/libs/importer/src/importers/base-importer.ts index 30a41134298..116a278e354 100644 --- a/libs/importer/src/importers/base-importer.ts +++ b/libs/importer/src/importers/base-importer.ts @@ -137,6 +137,10 @@ export abstract class BaseImporter { } protected parseXml(data: string): Document { + // Ensure there are no external entity elements in the XML to prevent against XXE attacks. + if (!this.validateNoExternalEntities(data)) { + return null; + } const parser = new DOMParser(); const doc = parser.parseFromString(data, "application/xml"); return doc != null && doc.querySelector("parsererror") == null ? doc : null; @@ -402,4 +406,10 @@ export abstract class BaseImporter { cipher.identity.lastName = nameParts.slice(2, nameParts.length).join(" "); } } + + private validateNoExternalEntities(data: string): boolean { + const regex = new RegExp("