Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Oc Pwnedpasswords Plugin Laravel Package

luketowers/oc-pwnedpasswords-plugin

An October CMS plugin that checks passwords against the Pwned Passwords (Have I Been Pwned) database to block known-compromised credentials. Adds validation to backend and frontend forms, helping keep accounts secure with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Winter CMS plugin (not a plain Laravel package), so treat it as a Laravel package with a CMS bootstrapping layer on top. It adds a HaveIBeenPwned check — via the k-anonymity range API — to password validation.

composer require winter/wn-pwnedpasswords-plugin
php artisan winter:up   # or october:up on October CMS

Then enable Winter.PwnedPasswords under Settings → System → Updates & Plugins (or add it to plugins/ / your composer.json extra.winter provider list if you manage the plugin set declaratively).

Where to look first:

  1. plugins/winter/pwnedpasswords/Plugin.php — this is where the validator extension is registered; note the exact rule alias and any settings/back-end hooks.
  2. The plugin README.md and lang/en/lang.php — the message shown to users on failure lives there.
  3. Settings / backend permission entries — the plugin typically wires itself into the backend user password flow, not just front-end forms.

First use case: enforcing the check on backend user passwords. That is the highest-value, zero-code win — install, enable, and backend password changes/resets are validated against the breach corpus. Then extend the same rule to your own front-end registration and password-reset forms.

Implementation Patterns

As a validation rule in your own controllers/forms. The plugin registers a validator extension during boot, so it composes like any Laravel rule:

// Verify the exact alias in Plugin.php — it may be `pwned`, `pwned_password`, etc.
$rules = [
    'password' => ['required', 'min:8', 'confirmed', 'pwned'],
];

Use it in FormController/Backend\Widgets\Form validation, in Validator::make() calls, and in custom Plugin::boot() listeners rather than duplicating the HTTP call yourself.

Layered password policy. Pair the breach check with length/entropy rules and October's own password policy so that a leaked-but-complex password is still rejected:

'password' => ['required', 'string', 'min:12', 'pwned', 'confirmed'],

Fail-open vs fail-closed. The rule performs an outbound HTTPS call. Decide explicitly what happens if the HIBP API is unreachable or slow:

  • Fail-open (recommended for availability) — catch the transport exception inside your own wrapper rule and log it, so a network hiccup in a HIBP outage doesn't block password resets org-wide.
  • Fail-closed (recommended for high-security contexts) — let the exception surface as a validation error.

Wrap the plugin rule inside a small custom rule if you need this behaviour, since you cannot easily change the plugin's own error handling without forking it.

Caching. Because of k-anonymity, the plugin sends only the first 5 hex chars of the SHA-1 and receives a bucket of suffixes. Cache these buckets (Cache::remember keyed on the 5-char prefix, TTL of hours/days) if you validate passwords at any volume — otherwise every registration/reset is a live round trip.

Testing. In your suite, either swap the rule out for your own fake, or use Laravel's HTTP client fakes if the plugin resolves through the container. For feature tests that aren't about password strength, dropping the rule from the rule array keeps tests hermetic and offline-safe.

Extension: override the user-facing error message through lang/ overrides rather than editing vendor files, and keep the plugin in composer.json rather than vendoring it.

Gotchas and Tips

v2.0.0 is a hard rename — this is the breaking change to plan for.

v1.1.2 and earlier v2.0.0+
Composer package luketowers/oc-pwnedpasswords-plugin winter/wn-pwnedpasswords-plugin
PHP namespace LukeTowers\PwnedPasswords Winter\PwnedPasswords

Upgrade checklist:

  • composer remove luketowers/oc-pwnedpasswords-plugin && composer require winter/wn-pwnedpasswords-plugin (a plain composer update will not do this for you).
  • Grep the whole codebase — including config/, your own Plugin.php files, migrations, seeders, and any class_exists()/App::runningInConsole() guards — for LukeTowers\PwnedPasswords and oc-pwnedpasswords. Update the use statements; a stale import fails at class-load time, not at boot, so it can slip past smoke tests.
  • Fix any composer.json extra.october/extra.winter provider entries and any CI scripts referencing the old package name.
  • Clear caches after upgrading: php artisan cache:clear && php artisan clear-compiled (plus a composer dump-autoload) — October/Winter aggressively caches plugin metadata and stale classmaps are a classic source of "class not found" after a rename.
  • The rename was already on main but unreleased, so v1.1.2 is genuinely the last old-namespace tag. Pin ^2.0 and don't rely on a 1.x patch to pick up the rename.

Other pitfalls:

  • Network dependency in dev/CI. Offline environments and air-gapped CI will produce validation failures or slow timeouts. Set a short HTTP timeout and stub the rule in tests.
  • Privacy is fine, but say so. Only a 5-character SHA-1 prefix leaves the server; the plaintext and full hash never do. This is worth documenting for security review — it's the reason this plugin is preferable to a naive "check the password against a local wordlist" approach.
  • The error message is user-facing. A blunt "this password has been pwned" message confuses non-technical users. Reword to something actionable: "This password has appeared in a known data breach. Please choose a different one."
  • Silent misconfiguration. If the plugin is installed but not enabled, validation silently passes. Add an integration test that asserts a known-breached password (password, 123456789) is actually rejected — a cheap regression guard against the plugin being disabled during a deploy.
  • Composer name convention changed. The package no longer follows the old oc- prefix; if you have tooling that regex-matches plugin package names, update it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route