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

Password Exposed Laravel Package

jord-jd/password_exposed

Check if a password has been exposed in a data breach using the haveibeenpwned.com API. Provides a simple password_exposed helper and a PasswordExposedChecker class, returning EXPOSED, NOT_EXPOSED, or UNKNOWN, with support for SHA1 hashes and PHP 7.1+.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Scoping one shippable slice of "improve account security." This package answers exactly one question — has this password appeared in a known breach? — which turns a vague epic into a testable increment: block known-breached passwords at signup and password change, measure blocked attempts, credential-stuffing-related reset tickets, and support contacts. Ship in days, not a quarter.
  • Build vs. buy vs. framework-native — the decision you must actually make first. If you're on Laravel 8+, the framework already ships Password::min(8)->uncompromised(), which calls the same Pwned Passwords range API with k-anonymity. That means the honest framing is not "buy a security product," it's "adopt a maintained wrapper, use the built-in validator, or write 40 lines." This package earns its place when you need the check outside the validator pipeline — inside a registration service, a JSON API endpoint, an admin tool, a job, or a flow that already holds a SHA-1 hash rather than plaintext — or when you need an explicit tri-state instead of a pass/fail boolean.
  • The block-vs-warn and fail-open-vs-fail-closed policy call. PasswordStatus::{EXPOSED, NOT_EXPOSED, UNKNOWN} forces two product decisions to be written down rather than defaulted: do you hard-block on EXPOSED or warn-and-allow, and when the third-party API is down (UNKNOWN) do you reject the user or let them through? Fail-closed means an HIBP outage becomes your onboarding outage — that is a business-continuity decision, not an implementation detail, and it needs an owner before launch.
  • Where in the funnel it lives. Registration and password-reset/change are the cheap, high-value insertion points. Login-time enforcement is a different, far more disruptive product (it forces resets on existing users). There is no batch endpoint here, so retro-scanning your existing user table is a separate initiative with separate scoping — do not let it ride along as a "freebie."
  • Sequencing against MFA and rate limiting. This is an additive, low-cost control, not a fix for account takeover. Position it as a fast-following quick win alongside MFA and login throttling, not as the item that closes the ATO risk in your roadmap narrative.
  • Privacy and legal review posture. Only the first five characters of the SHA-1 hash leave your network; plaintext never leaves the app, and cache keys are prefix-based rather than full-hash (so your cache isn't a credential store). That materially shortens a DPO/security review compared with any alternative that posts credentials to a vendor — and it's the strongest single argument for this approach over a "just call an API with the password" shortcut.
  • Dependency-risk budgeting. Single maintainer, 223 stars, zero dependents, LGPL-3.0, but a genuinely active release trail (PHP 8.1–8.5 CI, Psalm, lint, response-parsing fixes, Composer constraint relaxations). Acceptable for a non-differentiating utility because the exit cost is low — you can vendor or rewrite it in an afternoon. Do not plan a fork around it; do plan the exit.
  • Latency and UX budget. Every check is a synchronous outbound HTTPS call (roughly 100–300 ms, first request per hash prefix). That's a UX decision: spinner on signup, timeout value, and what the user sees on UNKNOWN. Prefix-keyed caching makes steady-state cost negligible across a real user base, but the cold path is user-visible.

When to Consider This Package

Adopt if:

  • You're on PHP 7.1+/8.x (Laravel or otherwise) and want breach screening wired into registration/reset without new infrastructure or a vendor contract.
  • Your need sits outside Laravel's validator — service layer, API endpoints, queued jobs, hash-in-hand flows — where Password::uncompromised() doesn't reach.
  • You want the k-anonymity property available as a review artifact rather than something you implement and defend yourself.
  • You want an explicit UNKNOWN state so fail-open/fail-closed is a deliberate, auditable choice.
  • You're comfortable treating it as a thin, replaceable wrapper — and have accepted PSR-6/PSR-18 wiring as a small integration task, since Laravel's cache and HTTP client aren't PSR-6/PSR-18 natively and you'll likely pull in Symfony Cache and Guzzle.

Look elsewhere if:

  • You're on Laravel 8+ and only need signup-time blocking on a standard form — use the built-in uncompromised() rule and skip the dependency entirely.
  • You need offline/air-gapped checking, a locally hosted corpus, or a contractual SLA. This is a live third-party call with an UNKNOWN fallback, not a dataset you own.
  • You need bulk or retroactive scanning of an existing user table, or admin batch tooling. You'd be looping one API call per password.
  • You need email/account breach lookups — this covers passwords only.
  • You need a vendor with named support and security attestations, or counsel rejects LGPL-3.0 outright (a real consideration if you distribute the PHP app rather than operate it as a service).

How to Pitch It (Stakeholders)

To executives: This is a days-not-quarters security win with no new infrastructure, no vendor contract, and no new data leaving our systems in readable form — only a five-character hash prefix is transmitted, which keeps the privacy review short. It measurably reduces a well-understood attack path (credential stuffing against reused, already-breached passwords) at signup and password change, and it's fully reversible: one config change turns it off. Frame it as one of several cheap controls alongside MFA, not a replacement for them, and set the expectation that its value is risk reduction on new credentials, not remediation of existing accounts.

To engineering: Small surface area, framework-agnostic, DI-friendly — you can inject a custom PSR-18 HTTP client and a PSR-6 cache pool, and the package handles TLS validation via paragonie/certainty. It returns a three-state enum so error handling is explicit rather than implicit, supports SHA-1-hash input so plaintext can stay out of some code paths, and is CI-backed (PHPUnit, Psalm, lint on PHP 8.1–8.5). Caveats to state up front: one maintainer, zero dependents, LGPL-3.0 (check distribution model with legal), a synchronous outbound call on the cold path, and real wiring work for the PSR-6 cache and PSR-18 client in a Laravel app. Mitigate all of that by timeboxing the integration and keeping the call behind your own thin interface, so swapping to Laravel's built-in validator — or to 40 lines of your own — is a one-file change.

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.
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
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