Skip to content

Commit

Permalink
Fix XSS vulnerability in Firefox
Browse files Browse the repository at this point in the history
  • Loading branch information
bhollis committed Dec 17, 2023
1 parent fae867a commit 5109951
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 32 deletions.
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"eslint.packageManager": "yarn",
"eslint.validate": ["javascript", "typescript"],
"editor.codeActionsOnSave": {
"source.fixAll": true
"source.fixAll": "explicit"
},
"jest.jestCommandLine": "yarn test",
"[javascript]": {
Expand All @@ -19,5 +19,10 @@
"editor.codeActionsOnSave": {
"source.organizeImports": false
}
},
"[javascript][typescript]": {
"editor.codeActionsOnSave": {
"source.organizeImports": "never"
}
}
}
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## JSONView 2.5.0

- Fix a cross-site scripting vulnerability in the Firefox version of the extension.

## JSONView 2.4.3

- Fix recognizing content types like application/hal+json
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ JSONView

* [Install for Firefox](https://addons.mozilla.org/en-US/firefox/addon/jsonview/)
* [Install for Chrome](https://chrome.google.com/webstore/detail/jsonview/gmegofmjomhknnokphhckolhcffdaihd)
* [Install for Edge](https://microsoftedge.microsoft.com/addons/detail/jsonview/kmpfgkgaimakokfhgdahhiaaiidiphco)

Normally, when encountering a [JSON](http://json.org) document (content type `application/json`), Firefox simply prompts you to download the view. With the JSONView extension, JSON documents are shown in the browser similar to how XML documents are shown. The document is formatted, highlighted, and arrays and objects can be collapsed. Even if the JSON document contains errors, JSONView will still show the raw text.

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"startWindows": "Powershell.exe -File ./buildWindows.ps1",
"lint": "eslint src --ext .js,.ts --fix",
"watch": "npm-watch",
"rollup": "rollup"
"rollup": "rollup",
"tests": "http-server ./tests/"
},
"watch": {
"start": {
Expand Down Expand Up @@ -124,6 +125,7 @@
"eslint-plugin-array-func": "^3.1.8",
"eslint-plugin-github": "^4.7.0",
"eslint-plugin-radar": "^0.2.1",
"http-server": "^14.1.1",
"npm-watch": "^0.11.0",
"rollup": "^3.21.3",
"typescript": "^5.0.4",
Expand Down
28 changes: 0 additions & 28 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,6 @@ function isRedirect(status: number) {
return status >= 300 && status < 400;
}

/**
* Use the filterResponseData API to transform a JSON document to HTML. This
* converts to the same HTML that Chrome does by default - it's only used in
* Firefox.
*/
function transformResponseToJSON(details: chrome.webRequest.WebResponseHeadersDetails) {
const filter = browser.webRequest.filterResponseData(details.requestId);

const dec = new TextDecoder("utf-8");
const enc = new TextEncoder();
let content = "";

filter.ondata = (event) => {
content += dec.decode(event.data, { stream: true });
};

filter.onstop = (_event: Event) => {
content += dec.decode();
const outputDoc = `<!DOCTYPE html><html><head><meta charset="utf-8"></head><body><pre>${content}</pre></body></html>`;
filter.write(enc.encode(outputDoc));
filter.disconnect();
};
}

function detectJSON(event: chrome.webRequest.WebResponseHeadersDetails) {
if (!event.responseHeaders || isRedirect(event.statusCode)) {
return;
Expand All @@ -50,10 +26,6 @@ function detectJSON(event: chrome.webRequest.WebResponseHeadersDetails) {
isJSONContentType(header.value)
) {
jsonUrls.add(event.url);
if (typeof browser !== "undefined" && "filterResponseData" in browser.webRequest) {
header.value = "text/html";
transformResponseToJSON(event);
}
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ chrome.runtime.sendMessage({}, (response: boolean) => {
}

// At least in chrome, the JSON is wrapped in a pre tag.
const content = document.getElementsByTagName("pre")[0].textContent;
const jsonElems = document.getElementsByTagName("pre");
let content: string | null = null;
if (jsonElems.length >= 1) {
content = jsonElems[0].textContent;
} else {
// Sometimes there's no pre? I'm not sure why this would happen
content = document.body.textContent;
}
let outputDoc = "";
let jsonObj = null;

Expand Down
1 change: 1 addition & 0 deletions tests/xss.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"status":"success","message":"User Input received","userInput":"XSS<img src=x onerror=alert(origin)>"}
Loading

0 comments on commit 5109951

Please sign in to comment.