Open-source project
lithnet/ad-password-protection avatar
lithnet/ad-password-protection

Lithnet Password Protection puts breached password and complexity rules into Active Directory

Active Directory password filter featuring breached password checking and custom complexity rules

581 stars64 forksC#MIT

At a glance

What is it?
Lithnet Password Protection (LPP) is a password filter you install on Active Directory domain controllers, so that group policy controls can reject a password at the moment a user tries to set it, including checks against the Have I Been Pwned list, custom banned words and length-based complexity rules. It is MIT licensed, C# code, and the README also lists an auditing path for existing accounts that never pass through a change.
Who is it for?
LPP suits an organisation that wants its password policy enforced by the directory rather than by user education, since a password filter is the only place where a set password can actually be refused, and since the HIBP list and custom banned word stores cover the two cases that built-in AD complexity settings do not.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 16 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why a password filter rather than a policy setting

LPP is a module you install on your Active Directory servers that uses a password filter to inspect passwords as users attempt to change them. Using group policy, you customize the types of checks you want to perform on those passwords and they are either rejected, or approved, and committed to the directory.

That placement is the whole design decision. Active Directory already has a built-in complexity setting, and it is famously weak: it asks for three of four character categories and does not care about length, and it will happily accept P@ssw0rd1 on a system that has nothing else configured. A password filter changes the situation because it runs inside the directory's own password change path, on the domain controller, at the moment the credential is being set. A policy setting can ask for a stronger password. A filter can refuse the one being offered, which is a categorically different outcome.

The module is described as enhancing the options available to an organization wanting to ensure that all their Active Directory accounts have strong passwords, and the framing in the README is that LPP gives you the ability to take control of what a good password means to you, whether you want to adopt the 2018 NIST password recommendations in part, or in full. That NIST reference is worth noting, because the modern guidance is the opposite direction from what most complexity rules of the last two decades enforced: length is rewarded and character category requirements are dropped for long passwords, which is exactly what the length-based complexity option in LPP is built to do.

The project is written in C#, is MIT licensed, and its topics name active-directory, password and security. The last push to the repository was on 2026-10-07 and the repository is not archived.

The five checks you can switch on

The README lists the checks as a set of combinations you can enable, and each one addresses a different weakness in the default behaviour.

Blocking compromised passwords from being used is the headline. The project says it has made it super easy to import the HIBP data set, but you can also import any plain-text passwords or NTLM hashes that you can get your hands on. That second option matters more than it first appears: an organisation with its own list of passwords seen in past breaches can load that list instead, and the format flexibility means plaintext and hash imports are both supported rather than one being a special case.

Blocking passwords based on certain words is the second check, and the semantics are unusually well specified. Adding a banned word prevents it from being used as the base of a password, and the README's example is that adding the word password to the banned word store prevents not only the use of that word itself, but common variants such as P@ssw0rd, pa55word! and password123456!.

Defining complexity policies based on length is the third, and the example is the crux of the NIST-aligned approach. You can require number, symbol, upper and lower for passwords less than 13 characters, but have no special requirements for passwords 13 characters or longer. The summary of that is worth quoting, because it is the shortest statement of the philosophy: reward length, with less complexity.

The remaining two are the general purpose escape hatches. Regular expression-based policies let you define a regular expression that the password must match, or not match, and points-based complexity assigns points for the use of certain characters and categories and set a minimum point threshold a password must meet.

Points-based scoring is the one that is hard to get from built-in AD settings at all, since it lets you weight character classes rather than requiring them, so a long passphrase of lower-case words can outscore a short string that satisfies every category rule.

Normalization is what makes the banned word store practical

A banned word list is only worth having if it catches the way people actually write passwords, and the README is specific about how LPP handles that.

It says LPP is aware of common character substitutions and weak obfuscations and prevents their use through a normalization process. That is the mechanism behind the P@ssw0rd example in the previous section. Without normalization, a banned word store is a filter for the exact string and nothing else, and every user who types a variant gets through, which means the store is trivially defeated by anyone who types a variant. With normalization, the password is folded to a canonical form before the comparison happens, so substitutions and weak obfuscations land back on the banned base word.

The README does not document the specific normalization rules, so the exact behaviour is something you would need to confirm in the documentation site or by testing candidate passwords against the store before you rely on it for a given policy. That is a fair thing to want to know, because the difference between a rule that catches P@ssw0rd and one that does not is the difference between a policy that holds and one that is theatre.

This also explains why a custom banned word store is worth running alongside the HIBP check rather than instead of it. The HIBP list catches passwords that have appeared in public breaches. A banned word list catches passwords built on words specific to your organization, and only the second mechanism can know that a password is a variation of your product name, your city or your board member.

Auditing the passwords your users already have

Setting a password is only half the problem, and LPP addresses the other half in a way that is unusual for a filtering module.

The README says it also includes the ability to audit your users' existing passwords against the compromised password list, and that you will be able to find the weak and known compromised passwords, and force those users to change their password. A filter only sees passwords at the moment of change, so without an audit path a directory full of old weak passwords would stay that way indefinitely, and the new rules would only apply to new users and to users who happen to change a password for another reason.

The PowerShell module carries the tooling for this, and the README describes what the module is used to do. It can synchronize compromise password lists from the haveibeenpwned.com API, add your own banned words and compromised passwords as well as use popular 3rd party word and password lists, test passwords and existing hashes against the compromised store, and check to see if your user's current passwords in AD are found in the compromised password store.

That last capability deserves a note about where it comes from, because it is the least obvious thing in the project. The README credits the audit capability to the work Michael Grafnetter has done with his DSInternals tools, and it credits the HIBP integration to Troy Hunt's service. Reading a directory's current password hashes to check them against a compromise list is a security-sensitive operation, and knowing that the implementation rests on a known, separately reviewed set of techniques rather than on bespoke code is useful context for a security team reviewing the deployment.

One of the properties the README lists is that passwords never leave the domain controller, which is the answer to the obvious question about how an audit of current passwords is reconciled with a list of hashes. The comparison happens locally.

Deploying it on the domain controller

The getting started section is short, and it is worth being precise about what it does and does not tell you.

The instruction is to download the installer from the releases page, and then to read the getting started guide on the documentation site at docs.lithnet.io. There is no command line installation in the README and no configuration file to hand edit, because the configuration surface is group policy and the installation itself is a signed installer. That is a different shape from a typical open source project, and it is a deliberate one: this is code that loads into the credential path of a domain controller.

The system requirements are where the constraints are stated. LPP is only supported on x64 editions of Windows. For the password filter the requirements are Windows Server 2012 R2 or higher, and the Microsoft Visual C++ Redistributable package 2015-2022. For the PowerShell module the requirements are .NET Framework 4.7.2, Windows PowerShell 5, and the same Visual C++ redistributable.

Those numbers tell you what you are dealing with. The filter component needs a server role you already have, and the PowerShell component needs a Windows PowerShell host rather than PowerShell 7, which is a distinction that matters for anyone scripting the deployment in a modern environment.

The rest of the operational claims in the README are about the shape of the deployment. Passwords never leave the domain controller, the module is designed for large environments where high performance is required, it creates detailed event logs, it uses a DFS-R friendly data store, and no internet access is required and no additional servers are required for deployment. That last pair is the interesting combination. A module that must talk to an API to check passwords is a module that needs an egress path from a domain controller, so the design moves the synchronisation into the PowerShell module and lets the filter work against a local store.

Where LPP fits, and where it stops

The comparison worth making is with the built-in Active Directory password policies, and with the cloud-side password checks that now ship with identity providers.

Against the built-in policy, the difference is that AD can only request and cannot refuse beyond its built-in rules, while a filter can decide. The banned word store, the length-based complexity tiers and the points system all express policies the built-in screen cannot express, and the normalization behind the banned word store is what stops the obvious workarounds. The cost is that you now run third-party code on your domain controllers, in the path where credentials are validated, and the README itself acknowledges this, describing enterprise support agreements as a safety net for the decision to deploy third-party code on your domain controllers.

Against a cloud identity provider's breached password screening, the difference is where the check happens and what data it can reach. A cloud provider screens a new password against its own list at signup. LPP screens it inside your own directory against a list you control, which means you can bring your own HIBP import, your own third-party word lists, and your own local additions, and it means the existing-password audit reaches accounts that already exist. The trade-off is that LPP is Windows Server and Active Directory only, x64 only, and it does not extend the policy to any system outside your directory.

The limits are worth stating plainly. The README does not document the group policy configuration steps, the normalization rules, or the point allocation for the points-based complexity scheme, so the setup guide and the documentation site are the places to verify those before you commit to a policy. The audit capability reads existing password hashes from the directory, which is a decision your security team has to be comfortable with. And the module requires Windows Server 2012 R2 or higher with .NET Framework 4.7.2 and Windows PowerShell 5 for the management side.

On maintenance, the picture is a long-running product rather than a hobby. The releases are v1.1.120 from 2026-07-04, with v1.1.53 and v1.1.51 both from 2023, the last push was on 2026-10-07, and the project ships a paid enterprise support option alongside the MIT licensed code.

Editorial conclusion

LPP suits an organisation that wants its password policy enforced by the directory rather than by user education, since a password filter is the only place where a set password can actually be refused, and since the HIBP list and custom banned word stores cover the two cases that built-in AD complexity settings do not. It is the wrong tool if you cannot install unsigned or third-party code on your domain controllers, or if your directory is not Active Directory, because the mechanism is the Windows password filter interface itself. Before deploying, check the x64 requirement and the .NET Framework 4.7.2 and Windows PowerShell 5 prerequisites for the PowerShell module, and read the setup guide at docs.lithnet.io, since the README does not document the group policy configuration steps themselves.

Frequently asked questions

What does Lithnet Password Protection do for Active Directory?

It is a password filter module installed on Active Directory servers that inspects passwords as users attempt to change them, so group policy checks can reject or approve a password before it is committed to the directory.

How does LPP check passwords against the Have I Been Pwned list?

The PowerShell module synchronizes compromise password lists from the haveibeenpwned.com API and can also import plain-text passwords or NTLM hashes from other sources, then the filter rejects any attempted password found in the local compromised store.

Can LPP find compromised passwords on accounts that already exist?

Yes. It includes the ability to audit existing user passwords against the compromised password list, using capabilities that come from Michael Grafnetter's DSInternals tools, and the README says you can then force those users to change their password.

What are the system requirements for Lithnet Password Protection?

Only x64 editions of Windows are supported. The password filter needs Windows Server 2012 R2 or higher and the Microsoft Visual C++ Redistributable package 2015-2022, and the PowerShell module needs .NET Framework 4.7.2, Windows PowerShell 5 and the same redistributable.

How do I install Lithnet Password Protection?

Download the installer from the GitHub releases page and then follow the getting started guide on the documentation site at docs.lithnet.io. The README gives no command line installation because the configuration surface is group policy rather than a config file.

Does LPP need internet access or extra servers?

No. The README lists no internet access required and no additional servers required for deployment, along with a DFS-R friendly data store, which means the synchronization of compromise lists happens through the PowerShell module while the filter works against a local store on the domain controller.

Official sources

  1. Issues
  2. License: MIT
  3. lithnet/ad-password-protection on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lithnet-ad-password-protection.svg)](https://hysenlabs.com/projects/lithnet-ad-password-protection)

Was this useful?