Recovering stored credentials from a Windows server protected with AES encryption and DPAPI

Recovering stored credentials should be hard. On a recent engagement, it was not. Some of the systems we test look like they do everything right. This one passed every surface check. Then it handed over all of its stored credentials the moment someone looked past the label.


A system built with the right tools gives you a comfortable feeling. The encryption is modern. The operating system guards the secrets. No passwords sit in plain text. The architecture diagram uses all the right words. Most reviews stop there, because nothing on the surface looks wrong. That comfort is often where the real risk hides.

On this engagement we assessed an on-premises Windows platform. Sits quietly on a server and reaches across the network to do its job. Stored its passwords the way the guidance says to. Used strong encryption. Protected the encryption key with a mechanism built into Windows for exactly that purpose. On paper, you would sign it off. Yet any ordinary employee who could log in to that server could recover the key and read every stored credential. No administrator rights. Nothing most people would call an attack. We have removed anything that could identify the product or the client. The shape of the problem is what matters, and every organisation should care about it.

A design that did everything by the book

The application had a simple job. It needed to store a handful of stored credentials and keep working without a person present. Think of the login for its database, or an account it uses to reach other systems. These have to survive a restart. So the software cannot ask someone to type them in each morning. It saves them somewhere and reads them back on its own.

The team made sensible choices. They did not hardcode anything. They did not leave passwords in a readable file. Instead, they generated a unique encryption key for each installation. Then they handed that key to Windows to protect, using DPAPI, the Data Protection API that Windows provides for storing secrets safely. This is close to a model answer. It is the design you would hope to find.

So the interesting question is not what they did wrong. There is no single obvious mistake. The interesting question is how a set of reasonable decisions added up to something that failed completely.

How a local user recovered the stored credentials

Protecting a key is not one decision. It is several small ones. Each carries an assumption. Follow those assumptions and the picture changes.

The key guarded the wrong boundary

DPAPI can lock a secret in two ways. Its user scope lets only one account open the secret. Its machine scope lets anyone on that machine open it. This application chose the machine scope. So Windows did protect the key, but only against the outside world. It did nothing to stop the other people already on the server. Anyone who could log in could ask Windows to unlock it.

The backup lock was no secret

The software added a second lock on top. It asked for a secret value before anyone could open the key. On its own, that is a good idea. But the application built that value from information it left readable on the system. The method sat in its own code. So anyone who could read that information could rebuild the second lock exactly. A second lock helps only when the key to it does not hang right beside it.

The material sat in the open

Both pieces an attacker needs sat in the Windows registry. Its permissions let every user account on the machine read them. The installer set it up that way. So this was not one server that someone had misconfigured. It shipped like this on every installation.

No single one of these choices is a disaster. It is the way they line up that turns a well built system into an open one.

Put the three together and the result is quiet and complete. A standard, non-administrative user reads the protected key. They rebuild the backup lock from readable information. They ask Windows to unlock the key. Then they decrypt every stored credential the application holds. Almost anyone with an account on a shared server can do this. Every step uses the system exactly as designed. The attacker breaks nothing and overwrites nothing. To anyone watching the logs, it looks like ordinary activity, because it is.

One small missing piece, a much larger consequence

It would be easy to call this a one-server problem and move on. We push back on that hardest. Look at what those recovered stored credentials actually were. One of them was an account used across the wider network. A password like that does not stay on the machine it came from. It works as an identity elsewhere. With it, an attacker reaches other systems, moves through the environment, and gains ground far beyond the first host. It is a textbook case of what MITRE calls insufficiently protected credentials.

Hold on to the pattern. One overlooked detail. One setting chosen for convenience. One value left readable. Together they opened access across the network. The gap was small. What it led to was not. A weakness matters less for how it looks and more for what sits behind it.

If this sounds like your environment

This story is one example of a much broader family. Think of the on-premises platforms that discover, normalise, and enrich hardware and software information across an organisation. Businesses lean on them as a single source of truth for what they own and run. These platforms earn their value by reaching everywhere. That reach depends on stored credentials, often a domain or service account, so the software can authenticate across the estate on its own.

That same reach is what makes a weakness like this one matter. Maybe you build, sell, or run a platform in that space: IT asset intelligence, discovery and inventory, software or hardware asset management, or any centrally deployed system that keeps credentials to work across your environment. If so, this is worth a close look. The property that makes these tools useful is the same one that turns a single recovered credential into movement across your whole network.

Why an inventory of the right tools would have passed this

Here is the part that matters most, whatever your role. Check this system against a list of good practices and it passes. Strong encryption, present. Secrets under the operating system’s protection, present. No plaintext passwords, correct. A scanner hunting known-bad patterns finds nothing to flag. On every measure you can tick from a distance, the system looked fine.

The weakness did not live in any single item. Lived in the space between them, in the assumptions about who could reach what. It lived in whether the pieces held up once someone with real access pulled them apart. A checklist confirms that the parts are present. It does not confirm that they work together the way everyone assumes. You find that only when a person sits with the system. They follow each assumption to its end. They ask what happens if one turns out wrong.

How we actually test

This is the work we care about, and we are happy to be open about it, because none of it is magic. We do not take a label at face value. When a system says it protects its stored credentials, we ask a sharper question: protected from whom? Then we try it from the position of the people realistically on that machine, not just from the outside. We follow the whole chain. Trace the stored credentials back through the protection scope, the file and registry permissions, and every account that can touch a link in it. We look for the point where a convenient choice quietly cancels a careful one.

Most of what we find is not a dramatic exploit. It is a reasonable decision that stopped being safe the moment it met another reasonable decision. That kind of thing hides on an architecture diagram. It shows itself once you are inside. Anyone can call a design secure. Only testing tells you whether it is.

What this means, depending on where you sit

If you build software, secure design goes beyond choosing the right library. It lives in the assumptions around it: who can read a file, who can open a key, what a setting means once it ships. Give those assumptions the same attention you give the code.

If you run security, a clean scan and a finished checklist tell you the expected parts are present. They do not tell you the parts hold together against someone who is actively trying. Those are different questions. Automation answers only one of them.

If you own the business risk, the systems worth worrying about are often the ones that look finished and fine. A single missing piece in a quiet corner can reach much further than its size suggests. Finding it first costs far less than finding out later.

Everything worth protecting is worth testing

We did not write this up for the specific setting or the particular product. We wrote it for the shape of the thing. A capable team. Good tools. A design that looked right. And a gap that appeared only when someone tested it instead of trusting it. Encryption was never the weak part here. The key’s location, the people who could reach it, and the access it unlocked decided the outcome. None of that showed on the surface.

If this left you wondering what sits quietly in your own environment, follow that instinct. The systems that deserve a closer look are rarely the ones that already worry you. More often, they are the ones that look perfectly fine.

Curious what a closer look would find?

If any of this matched something in your own environment, we are happy to talk it through. No pressure, no assumptions. Reach out to our team and we can start with a simple conversation about where your real exposure sits.


This writeup describes a generalised pattern from authorised security testing. We have removed all product, environment, and credential details, and nothing here identifies a specific system or organisation.

← Back to Blog