Safeguard
Application Security•

CWE-260 Password in Configuration File: Moving Secrets Out of Config

A password in a config file is readable by anyone who can read the file, including backups and repos. CWE-260 explains the risk and safer alternatives.

Safeguard Security Team
5 min read

CWE-260 says the product stores a password in a configuration file that might be accessible to actors who do not know the password. It is a Base level weakness, not language specific, and it has several framework specific children, including an ASP.NET variant (CWE-13).

Config files are convenient. They are also copied, committed, backed up, attached to tickets and baked into images, which makes them poor places for secrets.

How it happens

Teams start with a working example. A database connection string goes into a file with a user name and password. That file is read by the application, so it needs to be readable by the service account. Over time it also becomes readable by deployment tooling, by developers, by backup jobs, and by whoever else touches the repository or the image.

# Vulnerable: a readable secret in a properties file
webapp.ldap.username=svc_app
webapp.ldap.password=correct-horse-battery
# Better: the file names where the secret comes from, not the secret
webapp.ldap.username=svc_app
webapp.ldap.password.file=/run/secrets/ldap_password
# The application reads the secret at startup and refuses to run without it
from pathlib import Path

def load_secret(path: str) -> str:
    value = Path(path).read_text().strip()
    if not value:
        raise RuntimeError("secret file is empty: " + path)
    return value

The file at that path should be readable only by the service account, and delivered by whatever secret mechanism your platform provides.

MITRE's observed example is CVE-2022-38665: a continuous delivery pipeline management tool stored an unencrypted password in a configuration file. Pipeline tools are a good example of why this matters, since they hold the keys to many other systems.

What an attacker gains

The record lists access control: gaining privileges or assuming an identity. MITRE's extended description is direct. This can result in compromise of the system for which the password is used. An attacker who reaches the file could learn the stored password or, worse, change it to one of their choosing.

Think about how many routes lead to a config file: a path traversal bug, a leaked backup, a public repository, a container layer pushed to a registry, a support bundle sent to a vendor.

How to find it

MITRE lists automated static analysis. Add these checks:

  • Search config files, templates, Helm values and compose files for keys such as password, secret and token that carry literal values.
  • Scan repository history, not only the current tree. A removed password is still in the commit log.
  • Inspect built images and artifacts, since a file that was deleted in a later layer can remain in an earlier one.
  • Check file permissions on deployed config. World readable is a finding.
  • Run a secrets scanner in CI so a new credential fails the build.

How to fix it

MITRE gives two mitigations, both in Architecture and Design.

  1. Avoid storing passwords in easily accessible locations.
  2. Consider storing cryptographic hashes of passwords as an alternative to storing in plaintext.

The second one applies when your product only needs to verify a password someone presents. When your product must present a password to another system, a hash is no use, so the first point carries the weight. In practice:

  • Keep the secret out of the file and out of version control. Inject it at deploy or run time from a protected store.
  • Give each secret to the smallest set of processes that need it, with restrictive file permissions.
  • Use separate credentials per environment, so a leaked development file does not open production.
  • Prefer credentials that expire or can be revoked, so exposure has an end date.
  • If a password has ever been committed or shipped in a file, rotate it. Deleting the line does not undo the exposure.
  • Keep example config files free of working values. Ship placeholders that make the application fail loudly until they are replaced.

Where the application and the config are shipped by someone else, check what they put in their defaults. Pipeline and build tools are worth auditing first, given what they can reach.

Which kinds of files count

Configuration is wider than people think. Besides properties and ini files, it covers environment files checked into a repo, compose and deployment manifests, CI pipeline definitions, connection strings in app settings, and files inside container images. Anything that holds a password and can be read by someone who does not already know it belongs in the search.

Include copies as well. Backups, support bundles, exported settings and attachments to tickets all carry the file out of its protected location. A password that is properly guarded on the server can still sit in plain view in a shared folder.

Try it yourself

Scan a sample repository and see which config entries are flagged as secrets.

Click through it at your own pace, or open it full screen.

Quick check

Is deleting a committed password enough?

No. It remains in version history and may exist in copies and images. Rotate it.

When does hashing help and when does it not?

Hashing works when you only verify a password a user presents. It cannot help when your product must send the password to another system.

What is the first mitigation MITRE lists?

Avoid storing passwords in easily accessible locations.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.