Sign inSign up

mfrankovic/edge-password-manager

By mfrankovic

Updated 2 months ago

Local Dockerized tool to bulk-manage passwords saved in Microsoft Edge - metadata only, no vault

Image
Security
0

1.4K

mfrankovic/edge-password-manager repository overview

Edge Password Bulk Manager

Build and push Docker image Docker Hub .NET 8

A local, containerized admin tool for bulk-managing the passwords Microsoft Edge already has saved for your Windows user. It lets you search, filter, categorize, multi-select and bulk-delete saved logins especially useful for wiping out large groups of entries by site, category (e.g. adult sites), duplicates, or an uploaded domain list.

This is not a password manager. It creates no vault, no cloud sync, and no separate password store. It operates directly on Edge's own local Login Data database and only ever reads/deletes metadata rows. It never decrypts, reveals, or exports passwords.


What it does

  • Profile & store discovery finds every Edge profile (Default, Profile 1, ) in the mounted User Data folder, across Stable/Beta/Dev, and every login database within each profile (see Multiple login stores below).
  • List saved logins origin URL, sign-on realm, username, created/last-used dates, times-used. Sortable grid, async loading.
  • Powerful filtering free-text, site/realm substring, username substring, duplicates-only, and category (adult, etc.).
  • Category tagging via blocklists loads domain blocklists and tags each entry (e.g. adult). Ships with a starter list and auto-loads any list you add.
  • Daily auto-refresh a background service re-downloads configured blocklist URLs every 24h (configurable) and reloads them. Manual "Refresh now" too.
  • Upload your own lists drop in a hosts/domain list through the UI, assigned to any category.
  • Smart selection select visible / invert / duplicates (keep newest) / never-used / insecure (HTTP) / by category / by uploaded domain list.
  • Bulk delete with safety dry-run report, preview, typed confirmation for large deletes, automatic timestamped DB backup, single SQLite transaction with rollback, per-row success/failure.
  • Restore & undo browse the backups this tool made and one-click restore, or undo last delete.
  • Cross-profile aggregate view and act across all profiles at once (deletes are routed to the correct profile DB).
  • Export metadata-only CSV (never passwords).
  • Stats & audit totals, adult/duplicate/insecure/never-used counts, and a local timestamped audit log (no plaintext passwords).
  • Opt-in update checks manually check GitHub Releases, or opt in to checking when the page opens, then copy the displayed Docker Compose update commands.
  • Dark/light mode, read-only mode, schema/debug panel.

How it works (and an important limitation)

Edge stores each saved login in a Chromium SQLite database named Login Data (table logins). Two very different kinds of data live there:

DataEncryptionUsed by this tool
origin_url, signon_realm, username_value, date_created, date_last_used, times_usedplaintextyes yes list, filter, delete
password_valueDPAPI + app-bound encryption (ABE)no never touched

Because passwords are protected by DPAPI and app-bound encryption (tied to your Windows user and Edge's own process), decryption is not possible from inside a Docker container and this tool deliberately does not attempt it. Your entire use case (searching and bulk-deleting by metadata) needs none of that, since all the metadata is plaintext.

The tool operates on a copy of the DB for listing (so it can read even while Edge is open) and on the live DB only for deletes/restores (which require Edge to be closed).

Multiple login stores per profile

A single Edge profile can contain several login databases, and recent Edge builds do not always use the file named Login Data:

FileWhat it is
Login DataLegacy/local store. On some installs this is stale.
Login Data NewThe active store on recent Edge builds where newly saved logins actually go.
Login Data For Account / For Account NewPasswords tied to the signed-in Microsoft account (sync).

If you only read Login Data, you can miss entries that Edge is really using (and deleting from a stale file has no visible effect). This tool therefore:

  • discovers every login DB in each profile (excluding *Backup* and journal/WAL/SHM sidecars);
  • lists each as a selectable store showing its last-modified timestamp, and marks the newest as *** active**;
  • defaults to the newest (active) store so it "just works";
  • offers an All stores (aggregate) view; and
  • routes every delete/backup/restore to the exact file a row came from so acting on the live store removes it from Edge, and you can still clean stale files deliberately.
Schema handling

The logins schema varies across Chromium versions. On load the tool runs PRAGMA table_info(logins) and:

  • selects only columns that actually exist (gracefully degrades if date_last_used, times_used, or blacklisted_by_user are missing);
  • deletes rows by the stable id column when present (modern Chromium), otherwise by the legacy composite key (origin_url, username_element, username_value, password_element, signon_realm);
  • converts Chromium timestamps (microseconds since 1601-01-01 UTC).

Project structure

EdgePassManager/
 EdgePasswordBulkManager.sln
 Dockerfile
 compose.yaml
 .env.example
 README.md
 CHANGELOG.md
 docs/
   RECOVERY.md
 tests/EdgePasswordBulkManager.Tests/
 src/EdgePasswordBulkManager/
    Program.cs
    appsettings.json
    Models/         EdgeProfile, LoginEntry, AppOptions, Results
    Helpers/        ChromiumTime, DomainHelper, DomainListParser
    Services/       ProfileDiscoveryService, LoginDatabaseReader, DeleteService,
                     BackupExportService, RestoreService, CategoryService,
                     ListRefreshService, AuditLog
    State/          PasswordManagerState (MVVM view-model)
    Components/      App, Routes, Layout, Pages/Home.razor
    adult-lists/    bundled starter blocklist

Build & run (Docker)

1. Configure
cp .env.example .env

Edit .env and set EDGE_USER_DATA to your Edge User Data folder, e.g.

EDGE_USER_DATA=C:\Users\<you>\AppData\Local\Microsoft\Edge\User Data
BIND_ADDRESS=127.0.0.1
HOST_PORT=8088
READ_ONLY=true
EDGE_MOUNT_MODE=ro

The defaults are a loopback-only, read-only preview. To enable backup, delete and restore operations, explicitly set both:

READ_ONLY=false
EDGE_MOUNT_MODE=rw

The application does not include LAN authentication. Keep BIND_ADDRESS=127.0.0.1 unless a trusted firewall or authenticated reverse proxy protects the port. To deliberately publish it on all interfaces, set BIND_ADDRESS=0.0.0.0.

2. Run
docker compose up --build -d

Open http://localhost:8088.

Pull the prebuilt image instead of building:

docker pull mfrankovic/edge-password-manager:latest
3. Manage
docker compose logs -f       # logs
docker compose down          # stop
docker compose up --build -d # rebuild after changes
docker compose ps            # includes container health status
Check for application updates

Open Application updates in the sidebar. The app shows its installed version and provides a manual Check for updates button. Automatic checks are disabled until you opt in; that preference is stored only in the current browser.

The checker reads the latest stable release metadata from GitHub. It does not download an image, access Docker, or run commands. When an update is available, it displays the release notes and these copyable commands for you to run from the folder containing compose.yaml:

docker compose pull edge-pass-manager
docker compose up -d --no-deps edge-pass-manager

Verify the updated container with:

docker compose ps
docker compose logs --tail 50 edge-pass-manager

Stable releases use version tags such as 1.1.0 and update the latest image tag. Builds from main publish under edge and do not become customer updates.

Persisted host folders (created next to compose.yaml):

  • data/backups DB backups taken before deletes/restores
  • data/exports CSV metadata exports
  • data/lists downloaded + uploaded blocklists
  • data/logs audit log

The container runs as the non-root .NET app account (UID 1654). Docker Desktop handles Windows bind-mount access. On Linux, create and restrict the persisted directories before startup:

mkdir -p data/{backups,exports,logs,lists}
chown -R 1654:1654 data
chmod -R u=rwX,go= data
Run locally without Docker (dev)
cd src/EdgePasswordBulkManager
dotnet run

Development config reads Edge from %LOCALAPPDATA%\Microsoft\Edge\User Data and writes artifacts under ./data. Edge database writes remain disabled by default; override EdgePassManager__ReadOnlyMode=false only for intentional local write testing.


Usage walkthrough

A typical "clean out a category of saved logins" session:

  1. Close Microsoft Edge completely. Deletes and restores need exclusive write access to the DB. Check Task Manager for lingering msedge.exe processes. (Listing/filtering works even while Edge is open it reads a copy.)
  2. Open the UI at http://localhost:8088.
  3. Pick a store in the left panel. Each profile lists its login DBs with timestamps; the newest is marked *** active** and selected automatically (usually Login Data New). Tick All stores (aggregate) to work across every store at once.
  4. Let the lists load. The status bar shows totals; the Category lists panel shows how many domains are loaded and when they last refreshed. Hit Refresh lists now to pull the latest blocklists on demand.
  5. Narrow it down with the filters: free text, site/realm substring, username substring, Category (e.g. adult), or Duplicates only.
  6. Select what to remove using the selection helpers:
    • Select adult sites / Select any flagged everything matched by your category lists.
    • Select duplicates (keep newest) every dupe except the most-recently-used per site+username.
    • Select never-used / Select insecure (HTTP).
    • Select by uploaded domain list upload your own list of domains to target.
    • Or tick rows manually / use Select visible, Invert.
  7. (Optional) Preview click Delete selected, then Dry-run report to see exactly how many rows would match before committing.
  8. Delete confirm in the dialog (large deletes require typing DELETE <count>). A timestamped DB backup is taken automatically first, and the delete runs in a single transaction.
  9. Changed your mind? Open Backups & restore Undo last delete (restores the newest backup) or Restore from backup to pick any snapshot. A safety backup of the current state is taken before restoring.
  10. Export a record anytime with Export CSV (metadata only never passwords).

Tips:

  • Toolbar Refresh re-scans profiles and reloads the current one.
  • Use Read-only mode (READ_ONLY=true in .env) for a safe look-but-don't-touch deployment.
  • The Schema / debug panel shows the detected logins columns and a live audit trail.

Category lists

  • Filename convention: files in the list directory are named <category>__<anything>.txt (e.g. adult__mylist.txt). Files without __ fall into the default category (adult).
  • Formats accepted: hosts (0.0.0.0 example.com), plain domains (example.com), #/! comments. Subdomains match a listed parent domain automatically.
  • Auto-refresh: configured under EdgePassManager:Categories in appsettings.json. The default includes the Block List Project "porn" list, refreshed every 24h.

Add another category by editing appsettings.json:

"Categories": [
  { "Name": "adult",    "Urls": ["https://raw.githubusercontent.com/blocklistproject/Lists/master/porn.txt"] },
  { "Name": "gambling", "Urls": ["https://raw.githubusercontent.com/blocklistproject/Lists/master/gambling.txt"] }
]

Safety & privacy

  • Close Edge before deleting/restoring. The DB is locked while Edge runs; the tool detects the lock and tells you.
  • Every delete/restore takes a unique, consistent SQLite snapshot first. Snapshots and staged restores must pass PRAGMA integrity_check; deletes run inside a transaction and roll back on error.
  • No passwords are ever decrypted, displayed, exported, or logged. CSV export and the audit log contain metadata only.
  • The default Docker binding is loopback-only. Blocklist URLs are the only outbound requests and must remain on HTTPS.
  • ReadOnlyMode and the read-only Edge bind mount are enabled by default for a look-but-don't-touch deployment.
  • Downloaded and uploaded lists are limited to 30 MiB and 2 million unique valid domains by default.

See Backup and recovery for the normal and emergency restore procedures.


Known limitations

  • No password reveal impossible in a container due to app-bound encryption (by design).
  • Deletes/restores require Edge to be fully closed (including background msedge.exe processes).
  • Very large blocklists (the default is ~930k domains, ~25 MB) use tens of MB of RAM expected.
  • Timestamps are shown in the server/container local time zone.

Tech

.NET 8 Blazor Server (interactive) Microsoft.Data.Sqlite Docker (Linux container). No third-party vault logic, no browser extension, no cloud services.

Tests

The regression suite uses temporary SQLite databases to cover modern and legacy deletion keys, dry safety controls, transaction rollback, WAL snapshots, unique backups, restore integrity, domain parsing, list-size enforcement and concurrent refresh protection.

dotnet test EdgePasswordBulkManager.sln -c Release
dotnet list EdgePasswordBulkManager.sln package --vulnerable --include-transitive

Tag summary

Content type

Image

Digest

sha256:3527d2648

Size

122.3 MB

Last updated

2 months ago

docker pull mfrankovic/edge-password-manager