Trace who can reach each Bitwarden collection and how

By General Input

Pick a collection and see every person who can open it, whether they got there directly or through a group, and fix the risky ones on the spot.

Integrations

  • Bitwarden
  • Slack Bot

Type

App

Categories

  • Operations
  • Engineering

Build me an internal security app that answers the one question my auditors and I ask constantly: who can actually reach this set of credentials, and how did they get in? The people using it are whoever administers our Bitwarden organization plus whoever is sitting in the audit meeting with them. Bitwarden's own admin console is member first, so answering this today means opening every group one at a time and reconstructing the picture by hand. This app is collection first. I start from the collection I care about and it shows me the full blast radius, all the way down to named individual people.

The app opens on a list of every collection in the organization, read from List Collections. Show each collection's name alongside how many groups reach it and how many distinct people that works out to, so the over exposed ones stand out immediately. Note that List Collections deliberately does not return group assignments, so those counts have to be assembled from List Groups, which does return each group's collection assignments. Let me mark any collection as sensitive and remember that marking between sessions. Default the sensitive flag on for names that look like production, money, or root access, for example Production Secrets, Prod, Root, Finance, Payroll, and let me correct it.

Picking a collection opens its blast radius view. The top section lists every group granted access to that collection along with the permission level each group holds, taken from List Groups, or from Retrieve Collection, which returns one collection including the groups assigned to it and their permission flags. Under each group, let me expand to every individual member inside it using Retrieve Group Member IDs. That operation returns member ids only, so join those ids against a single List Members call covering the whole organization rather than making one call per person. List Members supplies what I actually want on each row: name and email, role, invite status, whether two factor is enabled on that account, and the person's own direct collection access.

Every person row carries a clear badge saying whether their access is direct or inherited. Inherited means they reach the collection because they sit in a group that was granted it, and the badge should name which group. Direct means the collection appears in that person's own collection access from List Members with no group in between. Someone can be both, and when they are, say so prominently, because that is exactly the case where removing them from a group does not actually cut off their access, and I need to know that before I act.

Sort and highlight the risky cases at the top rather than making me hunt for them. Three things count as risky. First, anyone whose two factor is disabled, which is the worst case on a sensitive collection. Second, anyone still sitting in Invited status, meaning they were sent an invitation and never accepted it, so there is a standing offer of access to a person who may no longer need it. Third, anyone who reaches a sensitive collection through a group they probably should not be in. Flag that when the path runs through a broad catch all group, for example one named All Staff, Everyone, Contractors or Interns, or through a group whose membership is unusually large next to the other groups reaching that same collection. Let me also mark a group as one that is meant to stay narrow, and then flag it when it grows past that intent. Show the reason beside each flag in plain words, never colour alone.

When something looks wrong I want to fix it right there instead of filing a ticket, so give the rows inline actions. Removing a person from a group runs Update Member Groups, which replaces the full set of groups that member belongs to. Adding or removing someone on a group's roster runs Update Group Members, which replaces the full set of members assigned to that group. This is the single most important implementation detail in the entire app: Bitwarden's update calls are full replacements rather than partial edits, and any property left out of the body is reset to its default rather than preserved. So before changing anyone's groups, the handler must first read their current set with Retrieve Member Group IDs, apply only the one change I made, and send back the complete intended list. Same on the other side: read the group's current roster with Retrieve Group Member IDs before writing it back with Update Group Members. If it ever sends only the delta, it will silently wipe every assignment it did not include, which on a password manager is a real outage and not just a bad edit. Before each save, show me a confirmation naming exactly what is about to change and what is being preserved, then refresh the blast radius so I can see the new picture.

Give me a button that posts a summary of the collection and its risky members to our security channel using the Slack Bot Send a Message tool. Write it as something a colleague can read and act on: which collection, how many people reach it and through which groups, then the risky ones named with the reason, for example that Priya Shah has no two factor and reaches Production Secrets through the All Staff group. Keep it to readable sentences rather than a dump of ids or raw field names, and include anything I already fixed during this session.

Two constraints to design around. Collections cannot be created through the Bitwarden API, only edited, so do not offer a create collection action anywhere; if a collection is missing, the answer is to create it in Bitwarden and refresh. And member roles and statuses come back as integers rather than strings, so map them to the labels I actually recognise, Owner, Admin, User and Custom for roles, and Invited, Accepted, Confirmed and Revoked for status, everywhere they appear in the interface.

Related prompts

Explore more prompts
A brand asset library your marketing team actually searchesTurn Mailjet email clicks into ranked HubSpot follow-upsClean out the Looker dashboards and Looks nobody opensLiveKit live operations console for room moderationWake up dormant Keap leads with a researched reasonLiveChat coverage board for planning next week's shiftsPhone routing control panel for LiveKit voice agentsLinkedIn Ads budget pacing dashboard for every client accountGive your team Looker numbers without buying more seatsPause marketing emails to escalated customers, then restore them