Skip to main content

Free 30-min security demo  — We'll scan your real code and show live findings, no commitment Book Now

Offensive360
Vulnerability Research

Hardcoded Credentials Vulnerability (CWE-798): Checkmarx Fix & Remediation

Hardcoded credentials (CWE-798) are flagged by Checkmarx, Veracode, and Fortify as critical findings. Learn the exact remediation steps, how SAST scanners detect them, and how to fix hard-coded credentials across Python, Java, C#, and Node.js.

Offensive360 Security Research Team — min read
hardcoded credentials CWE-798 hardcoded passwords Checkmarx SAST secrets management hard-coded credentials remediation use of hardcoded password checkmarx

Hardcoded credentials — also called hard-coded credentials or hardcoded passwords — are one of the most consistently flagged findings in enterprise security assessments. Classified as CWE-798 (Use of Hard-coded Credentials), they appear in every major SAST scanner’s finding list: Checkmarx, Veracode, Fortify, SonarQube, and Semgrep all flag them as high or critical severity.

This guide explains what hardcoded credentials are, why SAST scanners flag them, how to interpret and fix the Checkmarx CWE-798 finding, and the correct remediation patterns for the most common languages.


What Are Hardcoded Credentials?

A hardcoded credential is any authentication secret — a password, API key, token, private key, or connection string — that is embedded directly in source code as a string literal, rather than being loaded from a secure external source at runtime.

// VULNERABLE — Checkmarx flags this as CWE-798
public class DatabaseConfig {
    private static final String DB_URL = "jdbc:postgresql://prod-db:5432/app";
    private static final String DB_USER = "admin";
    private static final String DB_PASS = "S3cur3P@ssw0rd!";  // <-- hardcoded credential

    public Connection getConnection() throws SQLException {
        return DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
    }
}

The problem is not limited to obvious password strings. Hardcoded credentials also include:

  • API keys and tokens: String apiKey = "sk-live-abc123..."
  • Private keys and certificates embedded as string literals
  • Connection strings with credentials: mongodb://user:pass@host/db
  • Default credentials that ship with firmware or containerized applications
  • Base64-encoded credentials: encoding does not constitute encryption

Why SAST Scanners Flag Hardcoded Credentials as Critical

SAST tools — including Checkmarx, Fortify, and Veracode — classify CWE-798 as high or critical severity because the attack surface created by hardcoded credentials is extraordinarily wide:

1. Git History Retains All Secrets Permanently

Once a credential is committed to a Git repository, it exists in the repository’s commit history indefinitely. Removing the credential in a subsequent commit does not expunge it from history. Tools like git log -S "password", truffleHog, gitleaks, and git-secrets can recover committed credentials instantly from any clone of the repository.

2. Every Person with Repository Access Has the Credential

This includes current developers, former employees who still have their local clone, contractors, third-party auditors, and anyone who has ever had read access — even after their access was revoked at the platform level.

3. Public Repository Exposure

GitHub, GitLab, and Bitbucket repositories that are accidentally made public are immediately scraped by automated bots searching for credential patterns. Exposed credentials are typically exploited within minutes.

4. Credential Rotation Is Impossible Without Redeployment

If a hardcoded credential is compromised, the only remediation is to change the credential in code, rebuild, and redeploy. If the credential has been in production for months, the window of compromise is the entire production lifetime.

5. Mobile and Binary Applications Expose Credentials to Reverse Engineering

Android APKs and iOS IPAs can be decompiled. Hardcoded API keys in mobile applications are routinely extracted using tools like jadx, apktool, and strings.


How Checkmarx Detects CWE-798

Checkmarx’s CWE-798 query (Use_Of_Hard_Coded_Password in Checkmarx CxSAST / Hardcoded_Credentials in Checkmarx One) uses data flow analysis to track string literals from their declaration through to security-sensitive method calls. It specifically looks for:

  • String literals assigned to variables whose names match credential patterns (password, passwd, pwd, secret, apikey, token, key, credentials)
  • String literals passed directly to authentication, connection, or encryption methods
  • Base64-encoded strings decoded and passed to sensitive methods (treated as obfuscated hardcoding)
  • String literals in configuration annotations (e.g., @Value("hardcoded") in Spring)

Understanding the Checkmarx Finding

When Checkmarx reports a CWE-798 finding, the result typically shows:

Severity: High / Critical
CWE: CWE-798
Query: Use_Of_Hard_Coded_Password
File: src/main/java/com/example/config/DatabaseConfig.java
Line: 15
Source: "S3cur3P@ssw0rd!"
Destination: DriverManager.getConnection(url, user, pass)

The source is the hardcoded literal. The destination is the sensitive sink where the credential is used. Checkmarx traces the data flow from source to sink.

False Positives in Checkmarx CWE-798

Checkmarx CWE-798 can generate false positives in the following cases:

  • Test credentials: Unit tests and integration tests often use fake credentials like "test123" or "password". These should be marked as false positives or refactored to use test-specific environment variables.
  • Non-credential variables named like credentials: A variable named passwordLength assigned the integer value 12 being reported in certain scanner versions.
  • Placeholder strings: Comments or documentation strings like "YOUR_API_KEY_HERE".

To suppress a legitimate false positive in Checkmarx, use the comment annotation rather than marking it in the platform without justification:

// checkmarx: false-positive - test environment credential, never used in production
private static final String TEST_PASS = "test-only-value";

How to Fix Hard-Coded Credentials: Remediation by Language

Python

# VULNERABLE
def get_db():
    return psycopg2.connect(
        host="prod-db.internal",
        user="admin",
        password="S3cur3P@ss"  # CWE-798
    )

# FIXED — Environment variables
import os

def get_db():
    return psycopg2.connect(
        host=os.environ["DB_HOST"],
        user=os.environ["DB_USER"],
        password=os.environ["DB_PASSWORD"]
    )

For applications that need structured secrets management, use a secrets manager:

# FIXED — AWS Secrets Manager
import boto3
import json

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

def get_db():
    creds = get_db_credentials()
    return psycopg2.connect(
        host=creds["host"],
        user=creds["username"],
        password=creds["password"]
    )

Java / Spring Boot

// VULNERABLE
@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder.create()
            .url("jdbc:postgresql://prod-db:5432/app")
            .username("admin")
            .password("S3cur3P@ssw0rd!")  // CWE-798
            .build();
    }
}

// FIXED — application.properties / environment injection
@Configuration
public class DataSourceConfig {
    @Value("${DB_URL}")
    private String dbUrl;

    @Value("${DB_USERNAME}")
    private String dbUsername;

    @Value("${DB_PASSWORD}")
    private String dbPassword;

    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder.create()
            .url(dbUrl)
            .username(dbUsername)
            .password(dbPassword)
            .build();
    }
}
# application.properties — values injected from environment at runtime
spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}

For Spring Boot with Vault or AWS Secrets Manager integration:

# application.yml with Spring Cloud AWS Secrets Manager
spring:
  config:
    import: "aws-secretsmanager:prod/myapp/db"

C# / .NET

// VULNERABLE
public class AppDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseNpgsql(
            "Host=prod-db;Database=app;Username=admin;Password=S3cur3P@ss"); // CWE-798
    }
}

// FIXED — IConfiguration injection
public class AppDbContext : DbContext
{
    private readonly IConfiguration _configuration;

    public AppDbContext(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseNpgsql(_configuration.GetConnectionString("DefaultConnection"));
    }
}
// appsettings.json — connection string value loaded from environment
{
  "ConnectionStrings": {
    "DefaultConnection": ""
  }
}
# Set environment variable at runtime
export ConnectionStrings__DefaultConnection="Host=prod-db;Database=app;Username=admin;Password=${DB_PASS}"

Node.js / JavaScript

// VULNERABLE
const mysql = require('mysql2');

const connection = mysql.createConnection({
  host: 'prod-db.internal',
  user: 'admin',
  password: 'S3cur3P@ssw0rd!',  // CWE-798
  database: 'app'
});

// FIXED — dotenv for development, real secrets manager for production
require('dotenv').config();

const connection = mysql.createConnection({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME
});

Secrets Management Solutions

Moving credentials to environment variables is the minimum viable fix that resolves the Checkmarx CWE-798 finding. For production systems, a dedicated secrets manager provides better security, audit trails, and rotation capabilities:

SolutionBest ForRotation Support
AWS Secrets ManagerAWS-hosted applicationsYes (automatic)
HashiCorp VaultMulti-cloud / on-premiseYes
Azure Key VaultAzure-hosted applicationsYes
GCP Secret ManagerGCP-hosted applicationsYes
DopplerDeveloper experience focusYes
1Password Secrets AutomationSmall teamsManual

Cleaning Credentials from Git History

Removing the credential from code does not remove it from Git history. If the credential was ever committed, assume it is compromised and rotate it immediately. Then clean the history:

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

# Replace all occurrences of the credential in history
git filter-repo --replace-text <(echo 'S3cur3P@ssw0rd!==>[REDACTED]')

# Force push all branches (requires repo admin rights)
git push origin --force --all
git push origin --force --tags

After History Cleanup

  • All collaborators must delete their local clones and re-clone
  • Invalidate any cached copies in CI/CD systems
  • If the repository was ever public, assume the credential is permanently compromised regardless of cleanup

Preventing Hardcoded Credentials in the Future

Pre-commit Hooks with gitleaks

# Install gitleaks
brew install gitleaks

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

SAST Integration in CI/CD

Running a SAST scanner in your CI/CD pipeline that flags CWE-798 before code merges is the most effective preventive control. Offensive360 scans for hardcoded credentials across C#, Java, JavaScript/TypeScript, PHP, Python, Go, Ruby, and more — and reports exact file and line locations so developers can fix them before deployment.


Summary: Fixing the Checkmarx CWE-798 Finding

StepAction
1Identify the hardcoded credential in the Checkmarx finding (source + line)
2Rotate/invalidate the credential immediately — assume it is already compromised
3Move the credential to an environment variable or secrets manager
4Clean the credential from Git history using git-filter-repo
5Add a pre-commit hook (gitleaks) to prevent re-introduction
6Re-scan to confirm the Checkmarx finding is resolved

The Checkmarx CWE-798 finding is one of the fastest to remediate once the pattern is understood. The code change itself is small — the critical step is credential rotation and history cleanup, which must happen regardless of how quickly the code is fixed.

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.