Safeguard
Application Security•

CWE-798 Use of Hard-coded Credentials: Find Them and Remove Them

Passwords and keys baked into code are shared by every install and impossible to rotate. See inbound and outbound forms of CWE-798, how to detect them, and how to fix them.

Safeguard Security Team
5 min read

CWE-798 is the use of hard-coded credentials, such as a password or cryptographic key, inside a product. It affects web and mobile apps, firmware and ICS/OT devices, and it is one of the easiest weaknesses for an attacker to exploit once someone has looked at the code or the binary.

How it happens

MITRE describes two variations.

Inbound. The product checks incoming credentials against a hard-coded set. Typically a default administration account is created with a simple password that is the same on every installation. Administrators usually cannot change or disable it without modifying the program or applying a patch, and it can be hard for them to notice.

Outbound. The product connects to another system and carries the credentials for that connection inside itself. Examples are database passwords, API tokens and signing keys in source files, config files or compiled binaries.

DB_URL = "postgres://admin:Summer2024!@db.internal:5432/app"   # outbound

def login(user, pw):
    if user == "support" and pw == "letmein":                  # inbound
        return True
    return check_database(user, pw)

Once code is shared, published, decompiled or pulled from a device, the secret goes with it. Strings in a binary are easy to extract.

The MITRE record lists observed cases in specialized software:

  • CVE-2022-40263: software for biological cell analysis had hard-coded credentials, leading to leak of protected health information.
  • CVE-2022-29953: condition monitoring firmware had a maintenance interface with hard-coded credentials.
  • CVE-2022-29960: an engineering workstation used hard-coded cryptographic keys that could allow unauthorized filesystem access and privilege escalation.

What an attacker gains

MITRE says that if hard-coded passwords are used, it is almost certain that malicious users will gain access to the account in question. The listed consequences include bypassing protection mechanisms, reading application data, gaining privileges or assuming identity, and executing unauthorized code or commands, with impact on confidentiality, integrity and availability.

Because the same credential works on every copy, one discovery compromises every deployment.

How to find it

MITRE lists several methods:

  • Black box. Credentials stored in configuration files can be found this way, but a hard-coded value inside code is much harder to spot from outside.
  • Automated static analysis. Published white-box techniques can detect hard-coded credentials.
  • Manual code review. Look for it where authentication is not delegated to a standard mechanism.
  • Manual dynamic analysis. For inbound credentials, use monitoring tools to examine how the product behaves when you present credentials.

Practical steps:

  1. Run a secrets scanner over source and over git history, since a removed secret is still in old commits.
  2. Scan build artifacts, containers and mobile packages, not just the repository.
  3. Search for default account names and for strings like password, secret, token and key near assignments.
  4. Rotate anything you find. Treat any secret that was ever committed as exposed.

How to fix it

From MITRE's mitigations, in plain steps:

  1. Outbound: keep passwords, keys and other credentials out of the code. Store them in a protected, encrypted configuration store or secrets manager that outsiders and other local users cannot read. Protect the key that protects the store. If you cannot encrypt, make file permissions as restrictive as possible.
  2. Inbound: do not ship a default username and password. Use a first-login mode that forces the user to set a unique strong password or key.
  3. If hard-coded credentials truly cannot be removed: apply access control checks and limit which entities can reach the feature that uses them, for example only from the system console and not over the network.
  4. Inbound passwords: store only strong one-way hashes with a random salt per password, and compare hashes at login.
import os

DB_URL = os.environ["DATABASE_URL"]       # injected at deploy time

def login(user, pw):
    record = users.get(user)
    return record is not None and verify_hash(pw, record.hash, record.salt)

Add a secret scan to your pull request checks so a new credential never reaches the main branch, and rotate on a schedule so a leak has a short life.

Try it yourself

This demo walks through a secrets scan, showing how exposed credentials are found and what to do next.

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

Quick check

Why is a hard-coded default admin password worse than a weak user password?

It is identical on every installation and usually cannot be changed without patching, so one leak exposes every deployment.

I deleted the secret from the repo. Am I safe?

No. It remains in git history and in any copy already made. Rotate it.

What replaces a default password?

A first-login flow that requires the user to choose a unique strong password or key.

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.