Skip to main content

Free 30-min security demo Book Now

Offensive360 Offensive360
Vulnerability Research

CWE-798 Use of Hard-Coded Credentials: Complete Reference 2026

CWE-798 complete reference: what hard-coded credentials are, why every SAST tool flags them Critical, detection patterns, and step-by-step remediation for Java, Python, C# and Node.js.

Offensive360 Security Research Team — min read
CWE-798 cwe 798 hard-coded credentials hardcoded credentials hardcoded passwords use of hard-coded credentials SAST secrets management CWE-798 remediation hardcoded secrets application security credential security

CWE-798 — Use of Hard-Coded Credentials is one of the most consistently exploited vulnerability classes in application security. It appears on the MITRE CWE Top 25 Most Dangerous Software Weaknesses, is flagged as Critical or High by every major SAST tool (Checkmarx, Fortify, Veracode, SonarQube), and is routinely exploited in real-world breaches — from exposed GitHub repositories to reverse-engineered mobile applications.

This is the complete reference for CWE-798: what it means, how it manifests in code, why it’s dangerous, how automated tools detect it, and how to fix it correctly across every major language.


What Is CWE-798?

CWE-798 (Use of Hard-Coded Credentials) is defined by MITRE as:

“The software contains hard-coded credentials, such as a password or cryptographic key, which it uses for its own inbound authentication, outbound communication to external components, or encryption of internal data.”

In plain terms: the application has a password, API key, token, private key, or connection string embedded directly in the source code as a literal value — rather than loaded from a secure external source at runtime.

CWE-798 is the parent weakness. It has two child weaknesses that SAST tools may also report:

CWENameDescription
CWE-798Use of Hard-Coded CredentialsParent: any hard-coded credential
CWE-259Use of Hard-Coded PasswordSpecifically a password literal
CWE-321Use of Hard-Coded Cryptographic KeySpecifically a cryptographic key

Most SAST tools report all three under the CWE-798 umbrella, but some vendors separate them. If your scanner reports CWE-259 or CWE-321, the remediation is identical.


What Counts as a Hard-Coded Credential?

CWE-798 covers more than just an obvious password = "abc123". Hard-coded credentials include any of the following embedded directly in code:

Passwords and passphrases

// VULNERABLE — CWE-798
private static final String DB_PASSWORD = "S3cur3P@ssw0rd!";
private static final String ADMIN_PASS = "admin";

API keys and access tokens

# VULNERABLE — CWE-798
STRIPE_API_KEY = "sk_live_51abc123..."
SENDGRID_API_KEY = "SG.abcdefg..."
OPENAI_KEY = "sk-proj-..."

Connection strings with embedded credentials

// VULNERABLE — CWE-798
private const string ConnectionString =
    "Server=prod-db;Database=AppDB;User Id=sa;Password=ProdPass123!;";

Private keys and certificates embedded as strings

// VULNERABLE — CWE-798
const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA7n...
-----END RSA PRIVATE KEY-----`;

Base64-encoded credentials

# VULNERABLE — CWE-798 (encoding ≠ encryption)
import base64
ENCODED_PASS = "U2VjcmV0UGFzc3dvcmQhMjAyNg=="  # base64 of "SecretPassword!2026"
password = base64.b64decode(ENCODED_PASS).decode()

Default credentials in firmware and container images

# VULNERABLE — CWE-798
ENV ADMIN_PASSWORD=default_admin_pass
ENV DB_ROOT_PASSWORD=mysql_root_1234

Hardcoded in configuration files committed to version control

# VULNERABLE — database.yml committed to git
production:
  username: app_user
  password: prod_database_password_here
  database: myapp_production

Why CWE-798 Is Rated Critical

SAST tools consistently rate CWE-798 as High or Critical severity. Here is why:

1. Every Developer with Repository Access Has the Credential

Once a credential is in source code, everyone who can clone the repository has it: current developers, former employees whose accounts were revoked but who kept their local clone, contractors, third-party auditors, open-source contributors. Access control at the repository level does not protect the credential itself.

2. Git History Is Permanent

Removing the credential in a new commit does not delete it from the repository. The credential remains accessible in every previous commit. Tools like truffleHog, gitleaks, git-secrets, and git log -S "password" recover committed credentials instantly from any complete clone.

# An attacker with a clone can recover all committed secrets
git log --all --full-history -p | grep -A 2 -B 2 -i "password\|secret\|apikey\|token"

3. Public Repository Exposure = Immediate Exploitation

GitHub, GitLab, and Bitbucket are continuously scanned by automated bots searching for credential patterns. A repository accidentally made public is typically scraped within minutes. Several high-profile cloud credential leaks have resulted in six-figure cloud bills within hours of exposure.

4. Credential Rotation Is Impossible Without Redeployment

A hardcoded credential cannot be changed without modifying code, rebuilding, and redeploying the application. This means a compromised credential may remain active throughout an extended breach investigation window.

5. Mobile and Binary Applications Are Reversible

Android APKs can be decompiled with jadx or apktool. iOS IPAs can be analyzed with class-dump. Compiled binaries can be inspected with strings. Hardcoded API keys in mobile applications are routinely extracted — this is CWE-798 in the mobile context.


Where CWE-798 Most Commonly Appears

Based on security assessment data across enterprise codebases:

LocationFrequencyRisk Level
Database connection stringsVery HighCritical
Third-party API keys (payment, email, cloud)HighCritical
Internal service authentication tokensHighCritical
Cryptographic keys for data encryptionMediumCritical
SMTP/mail server credentialsMediumHigh
Default admin credentials (firmware, IoT)HighCritical
CI/CD configuration filesMediumHigh
Container images (Dockerfile ENV)MediumHigh

How SAST Tools Detect CWE-798

SAST tools use two main detection strategies for CWE-798:

Pattern Matching

The scanner searches for variable names that match credential patterns combined with string literal values:

Pattern: (variable name contains "password", "passwd", "pwd", "secret", "apikey",
          "api_key", "token", "private_key", "credentials", "auth")
          AND (assigned a string literal value of non-trivial length)

This catches obvious cases immediately but can generate false positives on placeholder values like "YOUR_API_KEY_HERE" or "change_me_in_production".

Taint Flow Analysis

More sophisticated tools (including Checkmarx, Fortify, and Offensive360) track string literals through the code to identify when they reach authentication, encryption, or connection sinks:

Source: string literal "S3cur3P@ss" assigned to variable
Flow: variable passed to DriverManager.getConnection(url, user, pass)
Sink: authentication method called with literal value
Result: CWE-798 confirmed — literal flows to auth sink

Taint flow detection catches cases where the credential passes through intermediate variables or is concatenated into a connection string before reaching the authentication call.

Regex Pattern Libraries

SAST tools maintain regex libraries for specific credential formats:

  • AWS access key format: AKIA[0-9A-Z]{16}
  • Stripe API key: sk_(test|live)_[0-9a-zA-Z]{24}
  • JWT secrets embedded in code
  • Private key PEM headers: -----BEGIN (RSA |EC )?PRIVATE KEY-----
  • Connection string patterns for MySQL, PostgreSQL, MSSQL, MongoDB

Remediation: How to Fix CWE-798

The fix for CWE-798 is always the same principle: remove the credential from the codebase and load it from a secure external source at runtime. The implementation varies by platform.

Fix 1: Environment Variables (Minimum Viable Fix)

Environment variables are the simplest fix and are accepted as resolving the Checkmarx, Fortify, or SonarQube CWE-798 finding:

Java:

// VULNERABLE — CWE-798
private static final String DB_PASSWORD = "S3cur3P@ssw0rd!";

// FIXED — environment variable
private static final String DB_PASSWORD = System.getenv("DB_PASSWORD");

Python:

# VULNERABLE — CWE-798
DB_PASSWORD = "S3cur3P@ssw0rd!"

# FIXED — environment variable
import os
DB_PASSWORD = os.environ["DB_PASSWORD"]

C# / .NET:

// VULNERABLE — CWE-798
private const string DbPassword = "S3cur3P@ssw0rd!";

// FIXED — IConfiguration from environment
private readonly string _dbPassword;
public MyService(IConfiguration config)
{
    _dbPassword = config["DB_PASSWORD"];  // Reads from env var or appsettings
}

Node.js:

// VULNERABLE — CWE-798
const DB_PASSWORD = "S3cur3P@ssw0rd!";

// FIXED — environment variable (use dotenv for local dev)
require('dotenv').config();
const DB_PASSWORD = process.env.DB_PASSWORD;

Fix 2: Secrets Manager (Production Best Practice)

For production systems, a dedicated secrets manager provides credential rotation, audit logging, and fine-grained access control:

AWS Secrets Manager (Python):

import boto3
import json

def get_db_credentials():
    client = boto3.client("secretsmanager", region_name="us-east-1")
    secret = client.get_secret_value(SecretId="prod/myapp/database")
    return json.loads(secret["SecretString"])

creds = get_db_credentials()
# Use creds["username"] and creds["password"]

HashiCorp Vault (Java):

// Using Spring Vault
@Value("${secret.db.password}")
private String dbPassword;
// Spring Cloud Vault loads this from Vault at startup

Azure Key Vault (C#):

// In Program.cs / Startup.cs
builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{keyVaultName}.vault.azure.net/"),
    new DefaultAzureCredential()
);
// Access via IConfiguration as normal — no code change required

Fix 3: Configuration Files Outside Version Control

For local development, use .env files excluded from Git:

# .env (add to .gitignore — never commit this file)
DB_PASSWORD=your_local_dev_password
API_KEY=your_dev_api_key

# .env.example (commit this — documents required variables without values)
DB_PASSWORD=
API_KEY=

Always verify .env is in .gitignore:

echo ".env" >> .gitignore
git rm --cached .env 2>/dev/null || true  # Remove from tracking if already committed

Cleaning the Credential from Git History

Critical: Removing the credential from current code does not remove it from Git history. If the credential was ever committed, you must:

Step 1: Rotate the Credential Immediately

Assume the credential is already compromised. Change the password, revoke and re-issue the API key, rotate the encryption key — before doing anything else. The exposure window is the entire history of the repository.

Step 2: Remove from Git History with git-filter-repo

# Install git-filter-repo
pip install git-filter-repo

# Replace the exposed credential in all historical commits
git filter-repo --replace-text <(echo "S3cur3P@ssw0rd!==>[CREDENTIAL REMOVED]")

# Force-push all branches
git push origin --force --all
git push origin --force --tags

Step 3: Invalidate All Existing Clones

After a force-push rewrite, all collaborators must delete their local clone and re-clone. Cached copies in CI/CD systems must also be cleared. Any branch cached in a pull request that was opened before the rewrite retains the old history.


Preventing CWE-798 Recurrence

Pre-Commit Hook with gitleaks

# Install gitleaks
brew install gitleaks        # macOS
apt install gitleaks         # Ubuntu/Debian (or download from GitHub releases)

# Create pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
gitleaks protect --staged --redact --verbose
if [ $? -ne 0 ]; then
  echo "CWE-798: Potential credential detected. Commit blocked."
  exit 1
fi
EOF
chmod +x .git/hooks/pre-commit

CI/CD Pipeline Scanning

Run credential scanning on every pull request and every push to protected branches:

# GitHub Actions
- name: Scan for hardcoded credentials (CWE-798)
  uses: gitleaks/gitleaks-action@v2
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

SAST in the Merge Pipeline

A SAST scanner that checks for CWE-798 as part of every pull request merge gate prevents credentials from reaching the main branch. Offensive360 SAST flags CWE-798 findings at CI/CD integration time with the exact file, line number, and credential type — allowing developers to fix the finding before the merge is approved.


CWE-798 in Different Technology Contexts

Mobile Applications (Android / iOS)

Hardcoded API keys in mobile apps are a particularly high-risk variant of CWE-798 because mobile APKs and IPAs can be obtained by anyone who downloads the application:

// Android — VULNERABLE (CWE-798)
private static final String MAPS_API_KEY = "AIzaSyB1abc123...";
private static final String PAYMENT_API_KEY = "pk_live_51abc...";

For mobile applications, the fix is to serve sensitive API keys from a backend proxy — never embed them in the client application. Use Android’s BuildConfig + Gradle Secrets for keys that are absolutely required at build time, and rotate exposed keys immediately.

Infrastructure as Code (Terraform, Helm, Kubernetes)

IaC files committed to version control are a common source of CWE-798 findings:

# Terraform — VULNERABLE (CWE-798)
resource "aws_db_instance" "default" {
  password = "mysecretpassword"  # CWE-798
}

# FIXED — use variable with no default
variable "db_password" {
  type      = string
  sensitive = true
}
resource "aws_db_instance" "default" {
  password = var.db_password
}
# Kubernetes Secret — VULNERABLE if the base64 value is a real credential
apiVersion: v1
kind: Secret
data:
  password: bXlzZWNyZXRwYXNz  # base64("mysecretpass") — CWE-798

For Kubernetes, use external secrets operators (External Secrets Operator, Sealed Secrets) that store encrypted references rather than base64-encoded values.


CWE-798 and Compliance Frameworks

CWE-798 findings are relevant to multiple compliance frameworks:

FrameworkRelevant Control
PCI-DSSRequirement 2.2 — no default or hardcoded credentials in any system component
NIST SP 800-53IA-5 — authenticator management; credentials must not be hardcoded
OWASP Top 10A07:2021 — Identification and Authentication Failures
CIS ControlsControl 3.3 — ensure no sensitive data is stored in unsecured locations
SOC 2CC6.1 — logical access controls include credential management

Regulators and auditors will flag CWE-798 findings as evidence of inadequate credential management practices. A SAST report showing CWE-798 findings without mitigations will draw questions in a PCI-DSS QSA assessment or a SOC 2 audit.


Interpreting a CWE-798 SAST Finding

When your SAST tool reports CWE-798, the finding typically includes:

  • Severity: High or Critical
  • File and line: The exact location of the hardcoded credential
  • Snippet: The surrounding code showing the credential assignment
  • Remediation guidance: Whether to use environment variables or a secrets manager

Is it a false positive?

CWE-798 false positives occur when:

  • The “credential” is a placeholder like "REPLACE_ME", "YOUR_API_KEY", or "test"
  • The variable name resembles a credential but the value is not a real secret (e.g., passwordLength = 16)
  • The value is a test credential in a unit test context — mark it as false positive in your SAST tool with justification

To confirm the finding is a real credential: check whether the value looks like a real secret (entropy analysis), whether it is actually used in an authentication or encryption context, and whether it appears in any real deployed environment.


Frequently Asked Questions

Is CWE-798 always Critical severity?

Most SAST tools rate CWE-798 as High or Critical. The actual severity depends on what the credential grants access to: a hardcoded password for a production database is Critical; a hardcoded API key for a low-privilege read-only external service might be rated High. Never dismiss a CWE-798 finding without investigating what the credential controls.

Does CWE-798 apply to test credentials?

Test credentials that only exist in test environments and have no access to production systems are generally treated as low-severity or false-positive by security reviewers. However, they are still a code quality issue — if a credential is in the codebase and has the word “password” in the variable name, your SAST tool will flag it. The clean approach is to use clearly named constants like TEST_DB_PASSWORD_NOT_REAL = "only_for_unit_tests" and document them in your SAST suppression policy.

How do I fix CWE-798 in a legacy codebase with hundreds of findings?

Start with the highest-severity findings: production database passwords, payment API keys, and encryption keys. Rotate each credential first, then move it to environment variables or a secrets manager. Then clean git history. For a large legacy codebase, prioritize by the criticality of what the credential accesses rather than trying to fix all findings at once.

What is the difference between CWE-798 and CWE-312?

CWE-312 (Cleartext Storage of Sensitive Information) is about storing sensitive data without encryption — for example, saving a password to a log file in plaintext. CWE-798 is specifically about embedding credentials in source code. They can overlap (a hardcoded credential in source code is also cleartext storage), but CWE-312 is broader — it applies to databases, log files, config files, and other storage mechanisms beyond just source code.


Summary

CWE-798 (Use of Hard-Coded Credentials) is rated Critical by every major SAST vendor because any credential embedded in source code is effectively accessible to everyone who has ever had repository access — and once committed to Git, it cannot be fully removed without history rewriting and credential rotation.

The fix is always the same direction: move the credential out of source code and into environment variables, a secrets manager, or a secure configuration system that is never committed to version control. Then rotate the exposed credential, clean git history, and add pre-commit hooks and CI/CD scanning to prevent recurrence.

Offensive360’s SAST engine detects CWE-798 across all 60+ supported languages — including connection strings, API key patterns, private key PEM blocks, and base64-encoded credentials — and reports each finding with the exact file, line number, and credential type. Book a demo to get a complete inventory of CWE-798 findings with remediation guidance, or book a demo to see the platform in action.

Offensive360 Security Research Team

Application Security Research

Find vulnerabilities before attackers do

Run Offensive360 SAST and DAST against your applications and get a full vulnerability report in minutes.