Auto-connection for personal-files for Bitwarden Desktop

Hi! Bitwarden is currently looking to update the snap package of the Bitwarden Desktop app, but is unable to do so since we had changed permissions and added an interface / plug which needs permission.

Thank you for your consideration.

This request has been added to the queue for review by the @reviewers team.

hey @quexten , QQ on the request, I can see these personal files have been requested

        "personal-files": {
          "read": [],
          "write": [
            "$HOME/.config/chromium/NativeMessagingHosts",
            "$HOME/.config/microsoft-edge/NativeMessagingHosts",
            "$HOME/.config/google-chrome/NativeMessagingHosts",
            "$HOME/.mozilla"
          ]
        }

Shouldnt it be $HOME/.mozilla/native-messaging-hosts instead of the whole $HOME/.mozilla dir?

That would be preferred, yes, however firefox by default does not create the directory, so the desktop app creates it if it does not exist. If the user does not use any other native messaging application, then it would not be usable for them without running a command externally to set up the directory.

Thanks @quexten, that clarifies the intent, and the mechanism is right: personal-files emits one owner "<path>{,/,/**}" rwkl rule per entry, with no rule for the parent, so a scoped $HOME/.mozilla/native-messaging-hosts genuinely cant create ~/.mozilla when it is absent.

Where I would like to align before approving: the three Chromium paths have the exact same property: $HOME/.config/chromium/NativeMessagingHosts cant create ~/.config/chromium if missing either, but they’re scoped narrowly, so the “browser dir must pre-exist” constraint is already being accepted there. It would be good to apply the same remedy to Firefox rather than broadening, mainly because $HOME/.mozilla grants write to the whole profile (credentials, cookies, prefs) for all users, auto-connected, which is a big step up from “native messaging directory only.”

In practice the cold-start case is also narrow: using the Firefox host requires the extension installed in Firefox, which implies ~/.mozilla already exists and the scoped path works. So I would lean toward scoping to $HOME/.mozilla/native-messaging-hosts for consistency, does that work on your end? Feel free to correct me if I am missing something

thanks

On a side note, this will not work with Ubuntu default desktops for chromium or firefox where both come as a snap and use their $SNAP directory as home by default …

I also think the access should be limited to a Bitwarden specific configuration file, similar to what we did for keepassxc in Personal-files access request for KeePassXC. Other than that, It looks good to me

plugs:
  browser-native-messaging:
    interface: personal-files
    write:
      - $HOME/.mozilla/native-messaging-hosts/org.keepassxc.keepassxc_browser.json
      - $HOME/.config/chromium/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json
      - $HOME/.config/google-chrome/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json
      - $HOME/.config/microsoft-edge/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json
      - $HOME/.config/vivaldi/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json
      - $HOME/.config/BraveSoftware/Brave-Browser/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json
      - $HOME/.local/share/torbrowser/tbb/x86_64/tor-browser_en-US/Browser/TorBrowser/Data/Browser/.mozilla/native-messaging-hosts/org.keepassxc.keepassxc_browser.json

On a side note, this will not work with Ubuntu default desktops for chromium or firefox where both come as a snap and use their $SNAP directory as home by default …

That’s a good point. I saw that @James-Carroll mention Personal-files access request for KeePassXC - #11 by James-Carroll

“Specifically then, the FF snap is actually looking at $SNAP_REAL_HOME/.mozilla rather than its own snap $HOME because that’s where every non-sandboxed app would place them, so on with the rest.”

1 Like

@0xnishit I think there was some miscommunication on my end. We are not concerned about creating the .mozilla directory when absent, rather the native-messaging-hosts directory, which on mozilla is not created by default, but on chrome, the NativeMessagingHosts directory is created by default. It’s not that the browser dir must pre-exist, but the NativeMessagingHosts directory must.

If we gave permissions to just the native-messaging-hosts directory, then if the directory does not exist itself, a user would have to run a command outside of the sandbox to create it. We are trying to make setup as frictionless as possible here, so a user running a command to enable it feels like a step back.

@ogra Yes, snap-sandboxed browsers are not just yet supported. We want to, but the initial expansion of support includes flatpak browser, flatpak desktop app, snap desktop app (but not snap browsers).

Given that this works on keepassxc, I wonder if snap does not work in the same way that flatpak does…

@jslarraz I’ll note that because we want to support sandboxed browsers (snap, flatpak) just a native messaging manifest is not enough. It works for unsandboxed browser, but for sandboxed browsers, neither the unix socket nor the binary that the manifest tells the browser to invoke are available from within the sandbox. The workaround we found is to place a unix socket into the sandbox’ NativeMessagingHosts directory, along with a copy of the binary that allows the browser extension to talk to the desktop app. So we would have to add those files too for each directory.

I’ll loop back around to this as soon as I can. Thanks all for the feedback so far.

It’s not that Snap the package format works differently, it’s that Ubuntu has a downstream patch to the XDG Desktop Portals that allows for browsers with patches to use that interface to work with native messaging. The Firefox snap has this included by default, and the majority of Firefox snap users tend to be Ubuntu users, so there it works fairly comprehensively.

I swear when I tested the KeepassXC work originally it also worked on the Chromium snap, but apparently, Chromium does not have support and when I’d checked elsewhere, was told it never did.

It’s likely the Firefox Flatpak doesn’t have the patch at all but could be made to have it. If it did though, it’d still only work on Ubuntu & derivatives, because you need the system integration side of it which Flatpak/Snap themselves don’t provide.

I guess that’s with the intention to get Flatpak browsers to work; with the Ubuntu Portals patch, the KeepassXC snap provides the binary to the host system at /snap/bin/keepassxc.proxy - the sandboxed Firefox snap then doesn’t ever need to access that binary directly, because functionally it’s the portals/system operating outside the sandbox that create a bridge.

So for Firefox snap with BitWarden snap, you shouldn’t need to create a binary in Native Messaging folder the or expose a socket; but I can see why on Flatpak that looks essential, because the browsers wouldn’t have the Native Messaging Portals support. For non-sandboxed browsers, again, just the Native Messaging manifest should be enough so long as the executable for Bitwardens messaging proxy is exposed as a separate binary in /snap/bin/

You can only have a definition once though which I guess is the issue, so for the broadest compatibility, you’d basically have to treat the Flatpak browser approach as the standard approach for everything. Edit: And it’s not guaranteed to work that well with snapped apps if you did, because I don’t think personal-files grants executable permissions to the files it gives access to whereas e.g., home does, so even if Firefox snap has read access to the Native Messaging folder, it might not be able to execute the proxy.

3 Likes

Okay, looks like we’re skipping the current desktop app released until the permission question is resolved. I want to build consensus here on how to move forward.

We understand that XDG Desktop Portals has a solution on ubuntu, and seems to be enabled by default there, but this solution only works on ubuntu, not on other snap installations. (Though, granted, ubuntu is probably the vast majority of snap, other distros tend to use flatpak).

That said, so fair the assumption is that:

  • We need access to the entire firefox directory to create the NMHS directory
  • We need access to the entire NMHS directory on chromium based browsers, in order to place the sockets
    • As @James-Carroll points out, on Ubuntu this can be done by the XDG-Desktop-Portals based approach, however, we don’t have this implemented currently

In my opinion it is a reasonable assumption that a user trusts the Bitwarden snap because it stores all of their passwords. If the snap were malicious, then all of the user’s passwords (and SSH keys) would already be compromised.

On the NMHS vs NMHS + files permission, yes restricting to specific files in the NMHS would be more fine-grained, however, given that the browser is effectively running a binary that the bitwarden-desktop-app writes into the NMHS dir within the browser’s sandbox, this means that the desktop app could place any binary in there. Under the assumption that it were malicious, the entire sandbox could just be compromised by placing the compromised desktop proxy binary.

So, going forward, I see a few paths we can go:

    1. We move forward with auto-connect, in this case i’d actually like to modify the request to:
    •         "personal-files": {
                "read": [],
                "write": [
                  "$HOME/.config/chromium/NativeMessagingHosts",
                  "$HOME/.config/microsoft-edge/NativeMessagingHosts",
                  "$HOME/.config/google-chrome/NativeMessagingHosts",
                  "$HOME/.mozilla",
                  "$HOME/snap/firefox/common/.mozilla",
                  "$HOME/snap/chromium/common/chromium/NativeMessagingHosts",
                  "$HOME/snap/google-chrome/common/google-chrome/NativeMessagingHosts",
                  "$HOME/snap/microsoft-edge/common/microsoft-edge/NativeMessagingHosts"
                ]
              }
      
    • I have a draft PR that adds support for snap based browsers, and the next release would then add support for: snap to snap communication which would cover most Ubuntu users

    • This feels reasonable, because users should already place high trust in the Bitwarden snap, given it contains their passwords.

      • (If we provide the alternative of “install the deb please” this would give the Bitwarden app more permissions, while at the same time introducing more security risks because the deb currently does not support auto-updates, since Bitwarden does not host a repo for it)
    • Follow-Up improvement:

      • I will make a task to investigate the XDG-desktop-portal based approach. Once we moved to this approach, we can drop the permissions again.
    1. In case the snapcraft maintainers deem 1. as too risky.
      1. One path forward here would be to accept this, but not grant auto-connect. In this case upstream would add in-product UI to guide the user to grant auto-connect. We would prefer not to have the user run commands in the terminal because this would make it inaccessible to non-technical users.
      2. If 2.1 does not work, we would not support biometrics for the time being, until we have time to investigate xdg-desktop-portals for IPC.

From your sides, which approach would you prefer?

I can’t comment on the security review aspects since I’m not with Canonical, but I am thinking that adding an executable in the Native messaging manifests folder could have merit for user experience.

I think perhaps rather than adding the raw binary and socket to the Native Messaging folder, you might be able to get by with a shell script something similar to:

#!/bin/bash
if [[ -f /.flatpak-info ]]
then
  flatpak-spawn --host snap run bitwarden.proxy
else
  snap run bitwarden.proxy
fi

This still relies on the BitWarden snap defining a second executable to go in /bin/snap

My thoughts are that this might provide enough flexibility to cover unsandboxed, Flatpak, and Snap browsers

  1. Un-sandboxed browsers would just run as normal without portals, like how KeepassXC snap would work with e.g., Google Chrome
  2. Flatpak browsers would call out the sandbox and run without portals, I’m unsure if the browsers would need to add have permissions granted to use that command but it’s likely they already have them if it’s not a default capability.
  3. Snap browsers with the downstream portals patch would use the portals, so would be like the KeepassXC snap with the Firefox snap.
  4. Snap browsers without the downstream portals patch likely can’t benefit from that approach because they’ll either not have personal-files granted to let them access your binary, and I still think personal-files doesn’t actually grant executable permissions if they did, and then on top I think snap run doesn’t work inside snaps themselves.

This would mean you could also hide the socket, since it’d be an implementation detail kept entirely inside the snap runtime.

1 Like

Browsers in general do not get the host permission (and quite frankly I would not want them to either. I’d rather keep my browser within the confines of the sandbox). com.google.Chrome/com.google.Chrome.yaml at master · flathub/com.google.Chrome · GitHub . Maintainers in the past have also shown not open / unresponsive to more reasonable permission requests ( Add talk permissions to non-freedesktop dbus screensaver apis by quexten · Pull Request #316 · flathub/com.google.Chrome · GitHub ), so I doubt we can change much here. Maybe the situation for snap is better, but for flatpak this is not a path forward.

Thank you @James-Carroll for the insight and recommendations on this by the way.

1 Like

The current work for supporting snap-to-snap biometric unlock can be seen here: [PM-39608] [Shared Unlock] Snap Browser Extension Native Messaging Support by quexten · Pull Request #21487 · bitwarden/clients · GitHub .

Unless this approach is rejected, the only modification I’d like to make to my original request is the extra personal files listed in the PR:

"personal-files": {
          "read": [],
          "write": [
            "$HOME/.config/chromium/NativeMessagingHosts",
            "$HOME/.config/microsoft-edge/NativeMessagingHosts",
            "$HOME/.config/google-chrome/NativeMessagingHosts",
            "$HOME/.mozilla",
            "$HOME/snap/firefox/common/.mozilla",
            "$HOME/snap/chromium/common/chromium/NativeMessagingHosts",
            "$HOME/snap/google-chrome/common/google-chrome/NativeMessagingHosts",
            "$HOME/snap/microsoft-edge/common/microsoft-edge/NativeMessagingHosts"
          ]
        }
1 Like

There is no snap of the proprietary chrome, only of chromium, so this won’t be needed for the moment

2 Likes

Some of what I’ve read implies that flatpak-spawn --host is always allowed? At least e.g., here [Feature request]: Implement a permission flag for allowed commands for flatpak-spawn on host · Issue #5538 · flatpak/flatpak · GitHub it’s heavily implied and looking at some other Flatpak’s I’m familiar with where it’s advertised by the packager as available, they don’t seem to explicitly define it as a permission from what I can see.

I could be wrong, but I am under the impression that browsers could use that functionality and the Flatpak sandbox doesn’t deny it by default, even accounting for the fact that yes, it’s a trivial sandbox escape mechanism (and why AppArmor actually blocks snaps trying to use the underlying interface on our end)

FWIW, I’ve currently been without a PC for a few months but I’m expecting one delivered this week so can take a more direct look in the next week or so as I start catching up on backlogs :slight_smile:

1 Like

Some of what I’ve read implies that flatpak-spawn --host is always allowed? At least e.g., here [Feature request]: Implement a permission flag for allowed commands for flatpak-spawn on host · Issue #5538 · flatpak/flatpak · GitHub it’s heavily implied and looking at some other Flatpak’s I’m familiar with where it’s advertised by the packager as available, they don’t seem to explicitly define it as a permission from what I can see.

A flatpak needs to have system talk permissions to org.freedesktop.Flatpak to use flatpak-spawn –host. Example: com.notepadqq.Notepadqq/com.notepadqq.Notepadqq.yaml at efea8c37dbf9fcdf456270c5c2aa8774b207137d · flathub/com.notepadqq.Notepadqq · GitHub . This one is heavily scrutunized and won’t be granted lightly because it essentially allows a sandbox escape.

So yes, it is denied by default.

1 Like

Thank you @ogra, I’ll remove it from the draft, and retract the request for this path and for edge. I’ve added brave since it was missing in the electron builder config.

1 Like

Cheers, I’ll take this away for later, the example I was looking at was net.cozic.joplin_desktop/net.cozic.joplin_desktop.yml at 3906817ef6e0959d4787c8bc87e0f3b73e8358c3 · flathub/net.cozic.joplin_desktop · GitHub versus the README saying it works and myself seeing users try it apparently with success and without using flatpak override (e.g., here)

From my non official side I personally think this should be eligible for auto connection, with the primary justification being publisher trust (as a a verified snap) and user expectations (as a password manager you already have all the credentials inside your sandbox and so the risk profile shifts towards encouraging better security practises user-side, which this request helps with) - the rest is just implementation details. A key detail being that you’re not placing binaries in the hosts $PATH, so the only way that potential escape can be utilised is by an extension reading the manifest to find it, and the browsers have their own permissions and signature checks going on, so the risk IMO is minimal because the only extension that should be interacting with that manifest are Bitwardens own where again the trust is already significant.

If flatpak-spawn can’t be used then it might mean when trying to get the Firefox snap working, you’d have have a UI toggle for users where the .json is rewritten with a different executable path, but the files would be the same and the justification the same (I don’t think you can rewrite the binary as snapped browsers can’t execute it so that’s using the portals approach with a second /snap/bin/ executable)

I’ll try play around with Flatpak on the weekend and let you know if anything pops up (primarily I’m still wondering how Joplins Flatpak is making use of flatpak-spawn here, or whether it historically worked differently and changed since and the README is out of date?)

So community +1 from me, which might be a +0 in reality but I think the benefits to users and ecosystem outweigh any risks here, the balance is favourable :blush:

1 Like

Thanks everyone and @James-Carroll , the portal explanation is the key piece here. Let me take the directory-creation assumption first, since it’s load-bearing, then the snap-browser paths.

“We need the whole .mozilla to create the NMHS directory”

This isnt required on current snapd, because snapd creates the missing intermediate directories for you. Since the 2.62 cycle (LP #1997598: https://bugs.launchpad.net/snapd/+bug/1997598), personal-files auto-creates any missing directories between $HOME and a write target on first run by a non-root user. It is now documented behaviour (ref: https://snapcraft.io/docs/personal-files-interface) If there are missing directories between $HOME and the target file or directory, these are created automatically when the associated application is first run by a non-root user.

So I wouldd ask to scope the Firefox entry to $HOME/.mozilla/native-messaging-hosts to match the three Chromium entries.

The snap-browser paths ($HOME/snap/firefox/common/.mozilla, $HOME/snap/<browser>/common/.../NativeMessagingHosts)

I would push back on these specifically. -1 from my end on these files, They’re cross-snap writes, with Bitwarden reaching into another snap’s private SNAP_USER_COMMON, which breaks the isolation boundary between snaps and couples Bitwarden to each browser snap’s internal layout. That’s outside what personal-files is intended for. And as @James-Carroll mentioned, it is the wrong mechanism for Ubuntu: the XDG-desktop-portal native-messaging patch already bridges snap browsers to a host-side proxy (the KeePassXC snap does this via keepassxc.proxy ), so nothing needs to be written into a browser snap’s sandbox, since the portal handles it outside confinement.

I would say, for now, my preference is a scoped auto-connect now for these file paths, plus the portal work for snap browsers:

"personal-files": {
  "write": [
    "$HOME/.config/google-chrome/NativeMessagingHosts",
    "$HOME/.config/chromium/NativeMessagingHosts",
    "$HOME/.config/microsoft-edge/NativeMessagingHosts",
    "$HOME/.mozilla/native-messaging-hosts"
  ]
}

and +1 from my end for auto-connection for personal-files these paths

2 Likes