Skip to content

Commit 4048694

Browse files
committed
Replace DOM-based entity decoding with the he.js pure JS library.
1 parent 50f73bc commit 4048694

4 files changed

Lines changed: 363 additions & 10 deletions

File tree

src/lib/he.js

Lines changed: 345 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/manifest.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
"common/RequestKey.js",
5252
"common/Policy.js",
5353
"common/locale.js",
54-
"common/Entities.js",
5554
"common/SyntaxChecker.js",
5655
"common/Storage.js",
5756
"ui/Prompts.js",

src/xss/InjectionCheckWorker.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ for (let logType of ["log", "debug", "error"]) {
1313
}
1414

1515
include("InjectionChecker.js");
16-
Entities = {
17-
convertAll(s) { return s },
18-
};
1916

2017
{
2118
let timingsMap = new Map();

src/xss/InjectionChecker.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ XSS.InjectionChecker = (async () => {
44
"/lib/Base64.js",
55
"/lib/Timing.js",
66
"/xss/FlashIdiocy.js",
7-
"/xss/ASPIdiocy.js"]
7+
"/xss/ASPIdiocy.js",
8+
"/lib/he.js"]
89
);
910

1011
var {FlashIdiocy, ASPIdiocy} = XSS;
@@ -1030,9 +1031,8 @@ XSS.InjectionChecker = (async () => {
10301031
if (await this.checkHTML(s) || await this.checkJS(s) || this.checkSQLI(s) || this.checkHeaders(s))
10311032
return true;
10321033

1033-
if (s.indexOf("&") !== -1) {
1034-
let unent = await Entities.convertAll(s);
1035-
if (unent !== s && await this._checkRecursive(unent, depth)) return true;
1034+
if (await this._checkEntities(s, depth)) {
1035+
return true;
10361036
}
10371037

10381038
if (--depth <= 0)
@@ -1050,8 +1050,7 @@ XSS.InjectionChecker = (async () => {
10501050
return true;
10511051

10521052
if (/[\u0000-\u001f]|&#/.test(unescaped)) {
1053-
let unent = await Entities.convertAll(unescaped.replace(/[\u0000-\u001f]+/g, ''));
1054-
if (unescaped != unent && await this._checkRecursive(unent, depth)) {
1053+
if (await this._checkEntities(unescaped, depth, u => u.replace(/[\u0000-\u001f]+/g, ''))) {
10551054
this.log("Trash-stripped nested URL match!");
10561055
return true;
10571056
}
@@ -1089,6 +1088,19 @@ XSS.InjectionChecker = (async () => {
10891088
return false;
10901089
},
10911090

1091+
async _checkEntities(s, depth, preTransform = null) {
1092+
if (!(preTransform || s.includes("&"))) return false;
1093+
let value = preTransform ? preTransform(s) : s;
1094+
for (let opts = {isAttributeValue: true}; ; opts.isAttributeValue = false) {
1095+
let heDecoded = he.decode(value, opts);
1096+
if (heDecoded !== s && await this._checkRecursive(heDecoded, depth)) {
1097+
return true;
1098+
}
1099+
if (!(opts.isAttributeValue && heDecoded.includes("&"))) break;
1100+
}
1101+
return false;
1102+
},
1103+
10921104
_checkOverDecoding: function(s, unescaped) {
10931105
if (/%[8-9a-f]/i.test(s)) {
10941106
const rx = /[<'"]/g;

0 commit comments

Comments
 (0)