Bulwarden

Description

Bulwarden is the site agent, installed on each managed
WordPress site. It exposes a signed REST API (jgm/v1) that a Bulwarden
hub
calls to read health and security data and to trigger updates. The hub
is a separate application — it is not part of this plugin — and this plugin
talks to no hub at all until you pair it with one.

Features

  • Site health snapshots (versions, pending updates, disk, WordPress Site Health tests)
  • Full plugin & theme inventory (version, active status, available update) per site
  • Configuration-level security checks with a posture score
  • Remote core / plugin / theme updates, wrapped in maintenance mode
  • Zero-knowledge encrypted backups: the passphrase stays on your server and is never transmitted
  • A dashboard card showing who maintains this site and how to reach them

Pairing

On activation the plugin provisions an API key + secret. Copy the connect
string
from the Bulwarden entry in the WordPress admin menu and paste
it into the hub’s “Connect a site” form. Your provider’s support details are
then pushed to the site automatically by the hub and appear on the dashboard.

Security

Hub client requests are authenticated with the per-site API key and an
HMAC-SHA256 signature over the method, route, timestamp, and body. Timestamps
outside a 5-minute window are rejected to limit replay. The secret never
travels on the wire — it lives only in this plugin and in the hub webapp.

Privacy

Bulwarden is a client agent: on its own it sends data nowhere. Pairing this
site with a hub (yours, or your maintenance provider’s) is an explicit,
opt-in action — you choose when to copy the connect string from the Bulwarden
screen in the WordPress admin menu and hand it to that hub. Nothing is
transmitted before that.

Once paired, data only moves in these cases:

  • Health, inventory, and security checks. The paired hub reads these from
    this site’s signed REST API when it polls or when a check is requested —
    WordPress/plugin/theme versions and update status, a full plugin & theme
    inventory, disk usage, and the configuration-level security posture score.
  • Backups, only when triggered (the Settings screen’s “Back up now”
    button, or a request from the paired hub): the full site is archived and
    encrypted on this server with a passphrase that is never transmitted
    anywhere, then the ciphertext is uploaded to the hub. Only someone who has
    the passphrase can decrypt a backup — the hub operator cannot read its
    contents.
  • Malware scan results, only when a scan is triggered (admin- or
    hub-initiated): findings (type, severity, file path, line, and a short
    excerpt) are sent to the hub that requested the scan.
  • Finishing an interrupted update, when the paired hub asks. Nothing is
    sent in that exchange; the site runs WordPress’ own database upgrade, or
    deletes an expired .maintenance lock file, and reports the outcome.

Independently of any hub pairing, this plugin verifies WordPress core and
wordpress.org-hosted plugin files by comparing local file hashes against the
public checksum APIs at api.wordpress.org and downloads.wordpress.org.
Those requests carry only what identifies the release to look up — the
WordPress version and locale, and each plugin’s slug and version. No file
contents, hashes, URLs or user data are sent: the reference checksums come
back and the comparison happens here, on this server.

Bulwarden does not call home on activation, does not collect analytics, and
stores data on no server this site hasn’t been explicitly connected to. The
hub itself is a separate service outside this plugin’s control; consult your
provider for how it handles the data described above.

External services

This plugin connects to the services below. Nothing here runs on activation.

Your Bulwarden hub

Bulwarden is the site-side agent for a hub — the management application an
agency or site owner runs to watch and maintain a fleet of WordPress sites. The
hub is a separate product and is not part of this plugin.

The default hosted hub is operated by Bulwarden at https://bulwarden.net/ —
terms of use: https://bulwarden.net/terms/ , privacy policy:
https://bulwarden.net/privacy/ . A hub can also be self-hosted, or run by the
maintenance provider you buy from, in which case this plugin talks to that
provider’s server instead and their terms and privacy policy apply.

No connection to any hub exists until you make one. You pair a site by
copying the connect string from the Bulwarden screen in the WordPress admin
menu and pasting it into the hub; before that the plugin contacts no hub at
all, and it never discovers or chooses one on its own. Once paired, data moves only in these cases:

  • When the hub asks for status. It reads this site’s signed REST API and
    receives WordPress/plugin/theme versions and update status, the full plugin
    and theme inventory, disk usage, the results of WordPress’ own Site Health
    tests, and the configuration-level security posture score.
  • When a backup runs (you press “Back up now”, or the hub requests one).
    The site is archived and encrypted here, with a passphrase that is never
    transmitted, and only the ciphertext is uploaded. The hub operator cannot
    read a backup’s contents without that passphrase.
  • When a malware scan runs (started by you or by the hub). The findings —
    type, severity, file path, line number and a short excerpt — are sent to the
    hub that asked for the scan.
  • When the hub pushes your provider’s support details — their name, logo,
    support address and accent colour — on connect and whenever they change
    them. Nothing is sent from the site in that exchange.

Every one of those requests is authenticated with this site’s own API key and
an HMAC-SHA256 signature; the shared secret never travels over the wire.

api.wordpress.org and downloads.wordpress.org

The malware scan verifies WordPress core and wordpress.org-hosted plugins
against their published checksums, using WordPress.org’s own public APIs at
https://api.wordpress.org/core/checksums/1.0/ and
https://downloads.wordpress.org/plugin-checksums/. This happens whenever a
scan runs, whether or not the site is paired with a hub.

These requests identify only the release being looked up: the WordPress version
and locale, and each installed plugin’s slug and version. No file contents,
hashes, site URL or user data are sent — the reference checksums are returned
and compared locally.

These are WordPress.org services, covered by the WordPress.org privacy policy:
https://wordpress.org/about/privacy/

Screenshots

Installation

Bulwarden is one half of a pair: this plugin runs on the site, and a hub runs somewhere else and manages it. Installing the plugin on its own does nothing until you pair it with a hub.

  1. Install and activate the plugin as you would any other — upload it under Plugins → Add New → Upload Plugin, or install it from the directory.
  2. Go to Bulwarden in the WordPress admin menu. The plugin generated an API key and secret for this site on activation; the screen shows a single connect string that carries the site name, URL and both credentials.
  3. Copy that string and paste it into your hub’s “Connect a site” form. That is the whole pairing step — there is nothing to type on this side, and no hub address to configure here.
  4. If you want encrypted backups, set a backup passphrase on the same screen. It never leaves this server, and it is required to restore. Keep it somewhere you will still have it after the disaster you are backing up against — nobody, including your hub operator, can recover a backup without it.

Do I need a hub?

Yes, for anything beyond installing it. The hub is separate software: use the hosted one, run your own, or use the one your maintenance provider runs. Until the site is paired, this plugin contacts nothing and does nothing.

Upgrading

Updates install like any other plugin. Your credentials, passphrase and settings survive an update; nothing needs re-pairing.

FAQ

Does this plugin send my site’s data anywhere on its own?

No. Before you pair it with a hub it contacts nothing at all, and it never
discovers or chooses a hub by itself. After pairing, data moves only for the
things listed under Privacy below — health checks, backups, malware scan
findings — and only to the hub you paired with.

Can the hub operator read my backups?

No, provided you set a passphrase. The archive is encrypted on this server
with a key derived from your passphrase, and only the ciphertext is uploaded.
The passphrase is never transmitted, so a hub holds bytes it cannot decrypt.
The same property is why nobody can recover a lost passphrase for you.

What happens if I deactivate or delete the plugin?

The site stops answering its hub, which the hub will notice and report as the
agent going unreachable. Deleting the plugin removes its settings, its audit-log
table and its working directories (see uninstall.php); backups already stored
on a hub are unaffected.

Does it work on multisite?

The plugin runs per site. A network-wide database upgrade is reported but not
performed — core’s own network upgrade screen walks every site in the
network, and that is where it belongs.

Why does the malware scan flag a file I know is fine?

The file-integrity check compares every core and WordPress.org-hosted file
against the checksums WordPress.org published for that exact release. A caching
or optimisation plugin that rewrites a stylesheet produces the same mismatch a
backdoor does, which is why “this file no longer matches what was published” is
reported as a fact rather than a verdict, and why non-executable files are
warnings rather than critical findings. Your hub can show you the actual diff.

What does it do to my site’s performance?

Nothing on page loads: there is no front-end code path. Backups and malware
scans are real work and run in the background across WordPress cron ticks, to a
time budget, so they do not block visitors. Health checks are answered on demand
when the hub asks.

Which PHP and WordPress versions are supported?

PHP 7.4 or newer and WordPress 6.0 or newer. Backups additionally need the
sodium extension (encryption) and either zlib or the zip extension
(archiving); the Settings screen tells you if either is missing.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“Bulwarden” is open source software. The following people have contributed to this plugin.

Contributors

Translate “Bulwarden” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

1.13.7

  • No change to the plugin. Like 1.13.6 it exists for the release itself: publishing to the plugin directory failed on the very first attempt, in the step that tells the directory which files a version has dropped — there was no previous version for this one to have dropped any, and the step could not cope with having nothing to do.

1.13.6

  • No change to the plugin itself — it is 1.13.5 under a new number. The screenshots on the plugin directory name the version they were taken from, so publishing them alongside a matching release is what keeps the listing and the download describing the same thing.

1.13.5

  • Fix: opening a running backup’s log squeezed it into the half of the panel beside the Cancel button, leaving the button stranded in the middle of a column of log lines. The log now gets the full width of the panel.
  • Fix: the progress bar for the encryption and upload phases sat empty at 0% for a few seconds after each page load, before the first update reached it — directly under a line already saying how much had been transferred. It now appears only once there is progress to draw.
  • Change: the encryption passphrase field no longer stretches the whole width of the panel.

1.13.4

  • Change: the Bulwarden screen has been rebuilt around the question it never answered — is this site actually protected right now. It opens with the connection, the encryption passphrase, the last backup and the last scan, each with its own state, and a site that has not been set up yet is walked through the three steps that finish it instead of being shown a disabled button and told to look elsewhere.
  • Add: a running backup now shows which phase it is in — database, files, encryption, upload — and its run log, which the site has been recording all along and never displayed. A failed or cancelled run stays on screen until something replaces it.
  • Add: the last scan is summarised with what it actually found, grouped by kind, and says plainly how much of the site could be checked against published originals and how much publishes none.
  • Add: a panel for what this server can do — PHP, the encryption extension, the archive backend, and whether WP-Cron is running — because a backup that never starts on one site is otherwise invisible from the admin.
  • Add: your provider’s support details, as pushed by the hub, are now visible on the screen rather than only on the dashboard.
  • Add: the connect string and API key can be copied with a button, and the secret is masked until you ask to see it.
  • Fix: the progress bar for the encryption and upload phases never appeared, so a long upload looked identical to a stalled one.
  • Fix: the button that removes a backup exclusion did nothing when the click landed on its icon.

1.13.3

  • Change: Bulwarden now has its own entry in the WordPress admin menu instead of sitting under Settings. It is a screen you come back to — to pair the site, set the backup passphrase, start a backup or read the activity log — not something configured once and forgotten.
  • Add: a Settings link on the plugin’s row on the Plugins screen, so the way to it is where you look right after activating.

1.13.2

  • Fix: an untouched WordPress could be reported as having a modified core file. WordPress publishes a separate package per language, and they differ in exactly one file it checks: wp-includes/version.php. The package a site installed is not the language it is displayed in — switching the admin language installs translation files and rewrites no core file at all — so a site whose two disagree (an English install later switched to German, or a German one switched to “Deutsch (Sie)”) had that one file compared against a package it never installed. It was reported as a critical modification on every scan, and nothing an operator could do would clear it. The package on disk now decides which checksums are fetched, and if WordPress.org publishes none for it, that one file is left unchecked rather than judged against another package’s.
  • Fix: core findings now tell the hub which package they were measured against, so the diff view can say why WordPress.org’s copy of version.php differs from a localized site’s rather than presenting it as an unexplained mismatch.

1.13.1

  • Fix: some untouched plugins were reported as modified. WordPress.org publishes more than one accepted copy of a file whenever a release’s repository copy and its downloadable zip drift apart — both are genuine, and a site can legitimately have installed either. Every published copy is now accepted, so a file matching any of them is clean. Affected files were reported as critical findings on plugins nothing had touched.
  • Fix: findings on those files now tell the hub every hash the file was measured against, so it can show you the diff instead of reporting that WordPress.org has no copy of the file.

1.13.0

  • New: your hub can now see — and finish — an update that changed this site’s files but never completed. The two that strand a site are a pending WordPress database upgrade (the “Database Update Required” screen every administrator is sent to, which the public site hides completely) and a leftover .maintenance lock from an update that died half-way. Both are reported to the hub, and both can be finished from it: the repair runs exactly what WordPress itself would have run, and nothing else.
  • New: a plugin waiting on its own database migration (WooCommerce, most commonly) is reported too. It is reported only — that migration belongs to its author and runs from their own screen.
  • New: a restore can now put back only the database, leaving every file on disk untouched. A bad content edit or a plugin that mangled its own tables is a database problem, and restoring the files alongside it would also undo every plugin, theme and core update made since the backup — including the security ones. Restores made by an older hub are unaffected and still restore everything.
  • Add: the health report now includes this plugin’s own version, so your hub can tell which sites are new enough for a feature before offering it rather than after failing.

1.12.0

  • New: when a file no longer matches the version published on WordPress.org, your hub can now show you the actual diff — the published file beside the one on your site, with the changed lines marked. A checksum mismatch on its own can’t tell a caching plugin rewriting an asset apart from a backdoor appended to a core file; this is what tells them apart. Findings now carry the release they were compared against and the hash they should have had, so the hub can prove the copy it fetched really is the published one.
  • New: POST /jgm/v1/file returns the current contents of a file, and only of a file the site’s own last scan flagged. It is not a general file read: anything not named by a finding is refused, as are wp-config.php, symlinks, paths outside the site, and files over 1 MB.

1.11.1

  • Fix: the malware scan called a site infected over files that cannot run. A stylesheet, image or font inside a plugin or theme that no longer matches its published release is now reported as a warning rather than as a critical finding — the usual author of a rewritten style.min.css is a caching or optimisation plugin, not an attacker, and the file cannot execute either way. It is still checked, still reported, and still scanned for signatures; code files (PHP, JavaScript, HTML, SVG) and WordPress core are unaffected.
  • Change: findings now say what was actually observed — “no longer matches the version published on WordPress.org” — instead of implying a verdict. A checksum mismatch means a file changed after it was installed, which is a fact about the file, not a diagnosis of the site.

1.11.0

  • Fix: sites intermittently reported themselves as unreachable to their hub, clearing again on the next check. Every signed request now carries a single-use nonce, so two legitimate requests that arrive in the same second are no longer mistaken for one being replayed and refused.
  • This release must be installed alongside the matching hub update — the two sign requests to each other, and the signing form changed on both sides at once.

1.10.4

  • Fix: the malware scan flagged a plugin’s readme file as “does not match the released version”. wordpress.org generates a plugin’s checksums once, at release, but authors keep editing the tagged readme afterwards (a “Tested up to” bump, a changelog typo), so this fired on most healthy sites. Readme, changelog and licence files inside a plugin or theme are now reported as informational instead of as a modified plugin — they are still checked, and code files are unaffected.
  • Fix: when file-integrity findings from several plugins were listed together, the section was titled after whichever plugin happened to sort first, so it named one plugin above a list that included others. Findings are now titled by what they are, with the affected plugin shown on each file.

1.10.3

  • Fix: a missing or broken component at boot (e.g. an interrupted plugin update that leaves the site with a mix of old and new files) no longer takes down every page on the site. Each boot component now initializes in isolation, the same way a single failing Site Health test already can’t break the rest of the health report.

1.10.2

  • Fix: the uploads-folder hidden-PHP check still had false positives after 1.10.1 on images whose embedded color profile or gamma curve happened to be readable-looking binary (a narrow, slowly-drifting run of bytes that lands in printable ASCII without being text — and, being copied verbatim into every thumbnail WordPress generates, showed up identically across a whole set of derivative image sizes). It now also requires the readable run to contain actual letters, which genuine injected PHP always has (a function name, a keyword, at least a superglobal like $_GET) and this kind of structured binary noise essentially never does.

1.10.1

  • Fix: the malware scan’s uploads-folder check for hidden PHP could flag a legitimate image as a false positive — JPEG/PNG data is effectively random binary, and a large enough image has a real chance of containing a bare <?= by pure coincidence. It now also requires readable text to follow the tag, which genuine injected PHP always has but random image data essentially never does.

1.10.0

  • Add: the malware scan’s file-integrity check now also covers your active theme, the same byte-for-byte verification core files and wordpress.org-hosted plugins already get. A custom or premium theme with no published release to compare against is reported as unverifiable rather than treated as a finding, exactly like a premium plugin.
  • Fix: the malware scan’s file-integrity check could wrongly report wp-includes/version.php as modified on a completely untouched WordPress install, on hosts where PHP’s own cached view of that file can briefly disagree with what’s actually on disk (e.g. after a core auto-update completes). The check now reads the version straight off disk instead of trusting that cache, and any other checksum mismatch is double-checked before being reported, in case it was caught mid-write.

1.9.0

  • Remove: white-labelling is gone. The plugin always appears as “Bulwarden” with its real author in the plugins list, and can no longer be renamed, re-attributed or hidden from users who don’t administer the site. Your provider’s name, logo and support address still appear on the dashboard support card — that part is unchanged.
  • Change: all of this plugin’s stored data moved to a bulw_ prefix, as the Plugin Directory guidelines require. There is no automatic migration: a site updated from an earlier release finds no stored settings, and has to be re-paired with its hub (Settings Bulwarden Regenerate credentials, then paste the new connect string into the hub). Note the backup passphrase has to be re-entered too, and existing backups still need the old passphrase to decrypt — keep it before you change it.
  • Change: the settings screen’s styles and scripts are now loaded as proper enqueued files instead of being written inline into the page, and two unnecessary loads of WordPress core files were removed.
  • Add: readme now documents every external service the plugin contacts, and what is sent to each.

1.8.0

  • Add: when your provider restores a backup to this site, it can now choose whether to also rewrite every URL/domain found in the database to this site’s own — on by default (unchanged), with the option to leave the restored content exactly as backed up, which matters when a backup is restored onto a different domain than the one it came from.

1.6.0

  • Add: every backup keeps a detailed run log — each phase with timings, per-table row counts, anything skipped or pruned and why, and the exact operation that failed. It shows live on the Settings screen while a backup runs, travels to your provider with every finished backup, and is attached to failure reports, so a failed backup can be diagnosed remotely without server access.
  • Add: chunked, resumable uploads. Large backups are now sent in small, individually retried pieces that resume mid-file after a network error, instead of one huge request that a proxy body-size limit or dropped connection could doom outright. Falls back automatically when the hub doesn’t support it yet. The old hard one-hour upload limit is gone — a genuinely stalled transfer still aborts within about 2 minutes, but a slow, healthy one is never cut off again.
  • Add: end-to-end integrity checks. The finished archive is verified on disk before it is encrypted (exact size, plus a full read-back of the archive index), and a SHA-256 of the encrypted blob travels with the upload so the hub can prove it stored exactly the bytes this site produced.
  • Add: a disk-space preflight refuses to start a backup that clearly cannot fit (based on the previous backup’s size), failing in seconds with a clear message instead of after an hour of work — or filling the disk under the live site.
  • Add: a new streaming archive writer builds the backup in a single pass with no rewrites — dramatically less disk I/O on large sites (a 400 MB test tree dropped from ~24 GB of rewrite traffic to zero) — and already-compressed media (images, video, archives) is stored without recompression, cutting CPU time on media-heavy sites. Requires only zlib; ZipArchive remains as a fallback.
  • Fix: several ways a database dump could silently come out incomplete are now hard failures instead — a dropped database connection mid-dump no longer masquerades as “table finished”, and a dump missing the options table is refused outright. Dumps are also taken as a single point-in-time snapshot, binary data is written in a corruption-proof form, database views are handled as views (previously their rows were duplicated as table data), and large rows can no longer exhaust memory.
  • Fix: an unreadable directory anywhere in the site (a root-owned folder, a mounted volume’s lost+found) no longer aborts the entire backup — it is skipped, recorded, and reported.
  • Fix: sites whose plugins or themes are installed as symlinks now get an explicit record that those directories were not archived, instead of silently missing data.
  • Fix: a backup run killed by the host no longer leaves its temporary working directory — including an unencrypted copy of the site — behind forever; leftovers are cleaned up at the start of the next run.
  • Fix: a restored backup no longer carries the “backup in progress” state of the run that produced it, which could block new backups on the restored site for up to an hour.

1.4.1

  • Fix: two phpcs:ignore comments in the 1.4.0 working-directory cleanup referenced sniff codes that don’t exist, so they didn’t actually suppress anything — the WordPress Plugin Check tool correctly flagged direct rmdir()/scandir() use. No functional change.

1.4.0

  • Add: a “Cancel backup” button on the Settings screen, shown while a backup is running. It works even if the backup process is wedged, not just when it’s responsive: it cleans up the working directory and notifies your provider immediately, rather than waiting for the process to notice.
  • Fix: a symlinked directory anywhere in the site (pointing at an ancestor, another site sharing storage, or a loop between two directories) could send the archiving step into unbounded recursion with no error — indistinguishable from a hang. Symlinked directories are no longer followed.
  • Fix: a stray Unix socket or FIFO under the site (e.g. a cache/queue backend’s socket file) could make the archiver hang indefinitely trying to read it. Only regular files are ever archived now.
  • Fix: an upload that stalls completely (a proxy or load balancer silently dropping an idle transfer) now fails within about 2 minutes with a clear error, instead of hanging for up to an hour.
  • Fix: every backup’s temporary working directory is now fully removed when it finishes — previously an empty folder was left behind after every single run, successful or not.

1.3.0

  • Add: live backup status — the Settings screen now shows which step a running backup is on (dumping the database, archiving, encrypting, uploading), its size, and upload speed, refreshed automatically while it runs. Your provider can now also query this status directly, so a backup that crashes without reporting back no longer leaves its record stuck at “running” forever.
  • Add: only one backup can run at a time; starting a second one while another is in progress is refused with a clear reason instead of the two colliding.

1.2.1

  • Fix: a phpcs:ignore comment for the backup-exclusions form field no longer covered the line it was meant to (Settings.php), and the repository now ships a .gitattributes pinning source files to LF line endings — no functional change.

1.2.0

  • Add: backup exclusions are now a plain editable list on the Settings screen (add/remove a directory row) instead of a freeform textarea, pre-filled with every exclusion currently in effect — including the defaults, which used to be invisible and hardcoded.
  • Add: new default exclusions for the folders the most common alternative backup plugins (UpdraftPlus, All-in-One WP Migration, Duplicator, BackupBuddy, Total Upkeep, WP Clone) use for their own local archives, so they no longer bloat every backup by default.
  • Add: a .git directory is now excluded wherever it occurs in the site tree (not just at the site root), and is pruned from the walk entirely rather than iterated and discarded — much faster on a site with a large repository history.
  • Fix: sites that already had a custom backup-exclusions list keep the protection that used to be hardcoded (the cache/upgrade exclusion) via a one-time migration, so upgrading can’t silently shrink what gets excluded.

1.1.1

  • Fix: the plugin’s own pre-branding default (Settings menu label, admin plugins-list name) is now Bulwarden instead of the generic Site Maintenance placeholder left over from before the rebrand — matches the hub’s own agency branding default, which already shipped as Bulwarden. An agency’s white-label branding still overrides it after a site is paired.

1.1.0

  • Add: the malware scan’s signature walk (Layer B) now skips any file already proven byte-identical to its published release by the checksum verifier (Layer A) — a pattern match inside code the vendor actually shipped isn’t evidence of compromise on this site, so it no longer gets reported.
  • Fix: the scan no longer flags its own installation folder. It isn’t hosted on wordpress.org so it was never checksum-verified, and its own pattern documentation quotes the very strings the signature scanner looks for — which the scanner was matching against itself.

1.0.2

  • Fix: text domain corrected to bulwarden (header and every translatable string). The 1.0.0 revert to jg-maintenance was itself a mistake: it matched this plugin’s source-repo folder name rather than its actual installed slug, which has shipped as bulwarden since 0.3.2.
  • Fix: the restore process’s self-protection check (skip this plugin’s own folder mid-restore, so it can’t overwrite the code that’s running it) was still checking wp-content/plugins/jg-maintenance and so silently failed to protect the real wp-content/plugins/bulwarden install.

1.0.1

  • Fix: resolved the remaining WordPress Plugin Check findings — the header/translatable-string text domain regression from 1.0.0 (see below), a stale Tested up to, and several false-positive warnings (direct file I/O in the backup/restore subsystem, direct $wpdb calls, set_time_limit() in background jobs, and core-filter lookups) now carry documented justification so they no longer flag.

1.0.0

  • Fix: text domain reverted to jg-maintenance everywhere (header and every translatable string). It must match the plugin’s slug/folder name, not the Bulwarden brand — the earlier switch to bulwarden broke WordPress.org’s text-domain convention despite matching the new name.
  • Add: a Privacy section documenting exactly what data is sent to a paired hub, and when.
  • Harden: encrypted backup uploads now honor a site’s configured HTTP proxy and verify TLS certificates the way the WordPress HTTP API does, rather than relying on raw curl defaults.

0.3.3

  • No plugin changes. Version bump only, to re-cut a release after a suite CI fix (release:maintenance/deploy:plugin were still looking up the pre-rebrand plugin slug).

0.3.2

  • Fix: main plugin file renamed to bulwarden.php to match the Bulwarden rebrand (the CI build looks up the file by plugin slug).

0.3.1

  • Rebrand: the plugin is now Bulwarden (user-facing strings, plugin header, and default branding).

0.3.0

  • Rebrand: the plugin is now Bulwark, the site agent for Bulwarden (user-facing strings and plugin header).

0.2.3

  • Backups: the archiver now tolerates files that are deleted or replaced mid-backup (e.g. another backup plugin rotating its own files) — the affected files are skipped and logged instead of aborting the whole backup.

0.2.2

  • Backups: admin-configurable exclusion paths (Settings JG Maintenance Backup exclusions) so directories the plugin can’t know about on its own — e.g. a legacy backup plugin’s folder — can be left out of the archive instead of bloating every future backup.

0.1.0

  • Initial scaffold: client agent with signed REST API, health + security collectors, remote updates, white-label settings. (Hub is a separate webapp.)