Skip to content
This repository was archived by the owner on May 27, 2019. It is now read-only.

Commit e32c41f

Browse files
eraydmax-baz
authored andcommitted
[SECURITY] Fix for credential leak vector #231 (fixes #230)
- Credentials are now discarded immediately as soon as the tab has loaded - Credentials are not supplied to any model login that occurs after the tab has loaded - If the domain requesting credentials is not the same as the domain that was launched, the user will be asked if they really want this.
1 parent 67c2ac5 commit e32c41f

File tree

1 file changed

+69
-33
lines changed

1 file changed

+69
-33
lines changed

chrome/background.js

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -99,46 +99,82 @@ function onMessage(request, sender, sendResponse) {
9999
// spawn a new tab with pre-provided credentials
100100
if (request.action == "launch") {
101101
chrome.tabs.create({ url: request.url }, function(tab) {
102+
var tabLoaded = false;
102103
var authAttempted = false;
103-
chrome.webRequest.onAuthRequired.addListener(
104-
function authListener(requestDetails) {
105-
// only supply credentials if this is the first time for this tab
106-
if (authAttempted) {
104+
105+
// listener function for authentication interception
106+
function authListener(requestDetails) {
107+
// only supply credentials if this is the first time for this tab, and the tab is not loaded
108+
if (authAttempted) {
109+
return {};
110+
}
111+
authAttempted = true;
112+
113+
// don't supply credentials for loaded tabs
114+
if (tabLoaded) {
115+
return {};
116+
}
117+
118+
// ask the user before sending credentials to a different domain
119+
var launchHost = request.url.match(/:\/\/([^\/]+)/)[1];
120+
if (launchHost !== requestDetails.challenger.host) {
121+
var message =
122+
"You are about to send login credentials to a domain that is different than " +
123+
"the one you lauched from the browserpass extension. Do you wish to proceed?\n\n" +
124+
"Launched URL: " +
125+
request.url +
126+
"\n" +
127+
"Authentication URL: " +
128+
requestDetails.url;
129+
if (!confirm(message)) {
130+
return {};
131+
}
132+
}
133+
134+
// ask the user before sending credentials over an insecure connection
135+
if (!requestDetails.url.match(/^https:/i)) {
136+
var message =
137+
"You are about to send login credentials via an insecure connection!\n\n" +
138+
"Are you sure you want to do this? If there is an attacker watching your " +
139+
"network traffic, they may be able to see your username and password.\n\n" +
140+
"URL: " +
141+
requestDetails.url;
142+
if (!confirm(message)) {
107143
return {};
108144
}
109-
authAttempted = true;
110-
// remove event listeners once tab loading is complete
111-
chrome.tabs.onUpdated.addListener(function statusListener(
112-
tabId,
113-
info
114-
) {
115-
if (info.status === "complete") {
116-
chrome.tabs.onUpdated.removeListener(statusListener);
117-
chrome.webRequest.onAuthRequired.removeListener(authListener);
118-
}
119-
});
120-
// ask the user before sending credentials over an insecure connection
121-
if (!requestDetails.url.match(/^https:/i)) {
122-
var message =
123-
"You are about to send login credentials via an insecure connection!\n\n" +
124-
"Are you sure you want to do this? If there is an attacker watching your " +
125-
"network traffic, they may be able to see your username and password.\n\n" +
126-
"URL: " +
127-
requestDetails.url;
128-
if (!confirm(message)) {
129-
return {};
130-
}
145+
}
146+
147+
// supply credentials
148+
return {
149+
authCredentials: {
150+
username: request.username,
151+
password: request.password
131152
}
132-
return {
133-
authCredentials: {
134-
username: request.username,
135-
password: request.password
136-
}
137-
};
138-
},
153+
};
154+
}
155+
156+
// intercept requests for authentication
157+
chrome.webRequest.onAuthRequired.addListener(
158+
authListener,
139159
{ urls: ["*://*/*"], tabId: tab.id },
140160
["blocking"]
141161
);
162+
163+
// notice when the tab has been loaded
164+
chrome.tabs.onUpdated.addListener(function tabCompleteListener(
165+
tabId,
166+
info
167+
) {
168+
if (tabId == tab.id && info.status == "complete") {
169+
// remove listeners
170+
chrome.tabs.onUpdated.removeListener(tabCompleteListener);
171+
chrome.webRequest.onAuthRequired.removeListener(authListener);
172+
173+
// mark tab as loaded & wipe credentials
174+
tabLoaded = true;
175+
request.username = request.password = null;
176+
}
177+
});
142178
});
143179
}
144180
}

0 commit comments

Comments
 (0)