Skip to content

Commit

Permalink
Tools/pm 3567 import xxe detection (#6918)
Browse files Browse the repository at this point in the history
* RegEx to prevent external entities from being imported in xml

* Adding the test case

* Changing the regex and updating test case description
  • Loading branch information
ttalty committed Dec 8, 2023
1 parent 31112d8 commit c4b31c9
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
17 changes: 17 additions & 0 deletions libs/importer/spec/base-importer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down Expand Up @@ -103,5 +107,18 @@ describe("BaseImporter class", () => {
expect(result).toBe(false);
},
);

it("parse XML should reject xml with external entities", async () => {
const xml = `<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE replace [
<!ELEMENT replace ANY>
<!ENTITY xxe "External entity">
]>
<passwordsafe delimiter=";">
<entry><title>PoC XXE</title><username>&xxe;</username></entry>
</passwordsafe>`;
const result = importer.parseXml(xml);
expect(result).toBe(null);
});
});
});
10 changes: 10 additions & 0 deletions libs/importer/src/importers/base-importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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("<!ENTITY", "i");
const hasExternalEntities = regex.test(data);
return !hasExternalEntities;
}
}

0 comments on commit c4b31c9

Please sign in to comment.