1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-30 00:03:30 +00:00

[PM-29271] Add referrer checking for vault messages (#18346)

* update message from vault handling to check against accounts or message sender

* update valid vault referrer logic to check all configured environments
This commit is contained in:
Nick Krantz
2026-01-29 09:58:31 -06:00
committed by GitHub
parent a4355dbcab
commit b51d3bf9da

View File

@@ -291,15 +291,21 @@ export default class RuntimeBackground {
}
break;
case "openPopup":
await this.openPopup();
await this.executeMessageActionOrOpenPopup(msg, this.openPopup.bind(this));
break;
case VaultMessages.OpenAtRiskPasswords: {
await this.main.openAtRisksPasswordsPage();
await this.executeMessageActionOrOpenPopup(
msg,
this.main.openAtRisksPasswordsPage.bind(this),
);
this.announcePopupOpen();
break;
}
case VaultMessages.OpenBrowserExtensionToUrl: {
await this.main.openTheExtensionToPage(msg.url);
await this.executeMessageActionOrOpenPopup(
msg,
this.main.openTheExtensionToPage.bind(this, msg.url),
);
this.announcePopupOpen();
break;
}
@@ -374,40 +380,55 @@ export default class RuntimeBackground {
* @param message
* @returns true if message fails validation
*/
private async shouldRejectManyOriginMessage(message: {
webExtSender: chrome.runtime.MessageSender;
}): Promise<boolean> {
private async executeMessageActionOrOpenPopup(
message: {
webExtSender: chrome.runtime.MessageSender;
},
messageAction: () => Promise<void>,
): Promise<boolean> {
const hasAccounts = await firstValueFrom(
this.accountService.accounts$.pipe(map((a) => Object.keys(a).length > 0)),
);
// When there are no accounts associated with the extension, only allow opening the popup
if (!hasAccounts) {
await this.openPopup();
return;
}
const isValidVaultReferrer = await this.isValidVaultReferrer(
Utils.getHostname(message?.webExtSender?.origin),
);
if (isValidVaultReferrer) {
return false;
// When the referrer is not a known vault and the message is external, reject the message
if (!isValidVaultReferrer && isExternalMessage(message)) {
return;
}
return isExternalMessage(message);
await messageAction();
}
/**
* Validates a message's referrer matches the configured web vault hostname.
* Validates that a referrer hostname matches any of the available regions' and current environment web vault URLs.
*
* @param referrer - hostname from message source
* @returns true if referrer matches web vault
* @param referrer - hostname from message source (should not include protocol or path)
* @returns true if referrer matches any known vault hostname, false otherwise
*/
private async isValidVaultReferrer(referrer: string | null | undefined): Promise<boolean> {
if (!referrer) {
return false;
}
const env = await firstValueFrom(this.environmentService.environment$);
const vaultUrl = env.getWebVaultUrl();
const vaultHostname = Utils.getHostname(vaultUrl);
const environment = await firstValueFrom(this.environmentService.environment$);
if (!vaultHostname) {
return false;
}
const regions = this.environmentService.availableRegions();
const regionVaultUrls = regions.map((r) => r.urls.webVault ?? r.urls.base);
const environmentWebVaultUrl = environment.getWebVaultUrl();
const messageIsFromKnownVault = [...regionVaultUrls, environmentWebVaultUrl].some(
(webVaultUrl) => Utils.getHostname(webVaultUrl) === referrer,
);
return vaultHostname === referrer;
return messageIsFromKnownVault;
}
private async autofillPage(tabToAutoFill: chrome.tabs.Tab) {