Montara Pass
Clients

Browser extension

Fill and save logins from the vault in Chrome and Firefox.

apps/extension is a Manifest V3 extension for Chrome, other Chromium browsers and Firefox 140 or newer (142 on Android). It uses the web app's lib/crypto module, so it reads and writes the same vault.

The vault itself is created in the web app. The extension signs in and unlocks an existing one.

Build and load

pnpm build:extension   # writes apps/extension/dist/chrome and dist/firefox
  • Chrome: open chrome://extensions, enable Developer mode, choose Load unpacked and pick apps/extension/dist/chrome.
  • Firefox: open about:debugging#/runtime/this-firefox, choose Load Temporary Add-on and pick apps/extension/dist/firefox/manifest.json.

The two builds differ only in the manifest: Chrome runs the background script as a service worker, Firefox as an event page with an add-on id.

Pointing it at a server

pnpm build:extension builds for https://app.montarapass.com. To use another server, turn on Settings → Self-hosted and enter its Server URL, such as https://pass.example.com/api. Only the origin is kept: the extension adds /api/v1/… itself, and links to the web app on the same origin.

pnpm --filter @montara-pass/extension watch builds in development mode, where the API and the web app run on separate ports. That build points at http://localhost:8080 and http://localhost:5173, and its settings show both as API server and Web app. apps/extension/.env overrides the defaults of either build (VITE_DEFAULT_API_URL and VITE_DEFAULT_APP_URL).

The API accepts extension origins without a CORS entry.

The popup

After signing in and unlocking, the popup shows:

  • Logins for the current site, each with a Fill button.
  • The whole vault, with search, a sort toggle and buttons to copy the username or the password.
  • Add, to save a login for the current site, with a password generator (20 characters by default).
  • Full screen, which opens the vault in a tab.

Full screen

The tab view has three columns: filters (all items, logins, secure notes, favorites), the list, and the selected item. The list is the wide column and shows each item's folder and when it was last used; the item beside it keeps a reading width. Passwords stay hidden until revealed. Items can be created and edited here, including their folder. A secure note is written in the same Markdown editor as in the web app, loaded when one is opened.

The owner of an item can Share it from here: the item's key is wrapped for the other user in the browser, as in the web app. Changing someone's access or taking it away is done in the web app, which re-encrypts the item for the people who are left. Folders, favorites and the trash are managed there too.

The side menu also holds a Password generator and Password health, the same two tools as in the web app. Health lists the logins with a weak password and those sharing one; Open shows the login in the vault.

When Fill is offered

A saved login is offered for a page when the page's host equals the saved host, or is a subdomain of it. www. is ignored on both sides.

Saved URLPageOffered
example.comlogin.example.comyes
login.example.comexample.comno
example.comexample.com.evil.netno

Fill touches the active tab only when it is clicked, and fills only visible username and password fields. The inline menu looks for login fields on every page.

The inline menu

The extension puts a badge inside the focused login field. Entering an empty login field opens a menu under it with the logins saved for that site; picking one fills the form. The menu stays away when the site has no saved login or nobody is signed in, and closes on typing. Esc closes it for the rest of the page. The badge, or Alt+↓ in the field, opens it at any time.

It is always on, which is why the extension asks for access to every site when it is installed: a content script runs on each page to find its login fields. Nothing about the page leaves the browser.

PieceWhere it runsWhat it can see
content.jsthe page, top frame onlythe page's fields, including what is typed into them; nothing from the vault
inline.htmla frame of the extension's own originthe unlocked keys and the logins for the site

The page around the menu can neither read the frame nor script it, and the content script never receives a password from the vault: the frame fills the form itself, the same way the popup does. The frame learns which site it is on from the browser's record of its tab, not from the page.

In a password field that is choosing a password, the menu also offers a generated one, with a button to draw another. Picking it fills the password and its confirmation, and keeps it for the save prompt straight away, so it is not lost if the form is sent in a way the extension does not notice. A field counts when it is marked autocomplete="new-password", comes with a second password field, or sits in a form or at an address that reads like a sign-up. Nothing is suggested on Montara Pass itself, where the password being chosen is the master password, or while the vault is locked.

A field gets the badge when it is a password field, a text field in a form that has one, or a field that takes a username or an email going by its type, autocomplete, name or id.

Clicks a page tries to borrow

Before filling, the menu checks that it is fully opaque, on top of the page and still on a site the login matches, and it ignores clicks in its first 300 ms. The menu sits in the browser's top layer; an overlay placed there after it that lets clicks through is not detected.

While the vault is locked the menu lists nothing and offers Unlock, which opens the popup.

Saving a login as it is submitted

When a form with a filled password field is sent, by a submit, a button or Enter, the content script hands the username and password to the background script, which keeps them in chrome.storage.session for that tab. On the page that follows, or on the same one once the form is gone, a prompt in the top right corner offers to save the login. It is the same kind of frame as the inline menu, so the page cannot read or script it.

Nothing is shown when the vault already has that username, or that password, for the site. Nothing is kept when nobody is signed in, or for the Montara Pass app itself, where the password typed is the master password. While the vault is locked the prompt offers Unlock first. Not now, Esc, closing the tab or five minutes without an answer drop the login.

A form the site refuses is offered as well: the extension sees that a form was sent, not what the site answered.

Site icons and last use

A login keeps the icon of its site inside its encrypted content, as a PNG of at most 64 pixels. The extension fetches it once, when the login is saved: the tab's own icon, then /favicon.ico, then the icons the page names in its <link> tags. The request goes to the site itself, with no cookies and no referrer, and no icon service is involved, so no third party learns which sites are in the vault. Every client then shows the icon without asking anyone; the web app shows it too, but cannot fetch one.

A login the user owns that has no icon yet, because it is older or was made in the web app, gets one the next time the extension lists the vault. That rewrites the item once, which moves its "Last updated". A site without an icon is remembered as such and keeps the keyhole. Logins shared by someone else are left alone.

Filling a login, from the popup or the inline menu, calls PUT /api/v1/items/:id/used. The time is shown as "Last used …", and the inline menu lists the account used last first. It is stored per member, so it follows the user to their other browsers and is not shown to the people a login is shared with. A server without the route is ignored: the login is filled all the same.

Where secrets are kept

WhatWhereCleared
Access and refresh tokenschrome.storage.localon sign out
Unlocked vault keyschrome.storage.session (in memory)after 15 minutes without use, when the browser closes, on Lock
Master passwordnowhereused once to unlock
A login just submitted, until it is saved or declinedchrome.storage.session (in memory)on save, on Not now, when the tab closes, after 5 minutes

Permissions

PermissionWhy
storageTokens, settings and the unlocked keys
activeTab, scriptingFill the page the user is looking at, on click
alarmsThe auto-lock timer
clipboardWriteCopy buttons
Host permission for every siteRun the inline menu's content script, and call a self-hosted server at any address

For Firefox the manifest also declares what leaves the browser (data_collection_permissions): authentication information and personally identifying information. That covers the sign-in email and password sent to the API and the encrypted vault stored there. Firefox shows it when the extension is installed; 140 is the first release that does, which is why it is the minimum version.

On this page