CWE 798 - Use of Hard-Coded Credentials

Disclaimer
  • The code provided is for **educational purposes** only and should not be used in a **production environment** without proper review and testing.

  • The provided code should be regarded as **best practice**. There are also several ways to remediate the Vulnerabilities.

  • The code provided **may contain vulnerabilities** that could be exploited by attackers, and is intended to be used as a learning tool to help improve security awareness and best practices.

  • The mitigations provided are intended to address **specific vulnerabilities** in the code, but may not be effective against all potential attack vectors or scenarios.

  • The code provided is not **guaranteed to be secure or free** from all vulnerabilities, and should be reviewed and tested thoroughly before being used in a production environment.

  • The code provided is **not a substitute for professional security** advice or guidance, and users should consult with a qualified security professional before implementing any security measures.

  • The authors and contributors of the code provided **cannot be held responsible** for any damages or losses resulting from the use of this code.

  • The code provided is provided "as is" without any warranties, express or implied, including but not limited to the implied warranties of merchantability and fitness for a particular purpose.

  • We do not have any sponsors or financial interests in any specific products or services, and the information provided is based solely on our own knowledge and experience.

  • The vulnerable and mitigated code samples provided on our platform are generated with the help of AI and sourced from the internet. We have made every effort to ensure that the code is accurate and up-to-date, but we cannot guarantee its correctness or completeness. If you notice that any of the code samples belong to you and you wish for it to be removed, please contact us and we will take appropriate action. We also apologize for any inconvenience caused and are committed to giving appropriate credit to the respective authors.

About CWE 798

Use of Hard-coded Credentials

This Vulnerability occurs when software systems that involve the use of credentials (such as usernames and passwords) that are hard-coded directly into the source code or configuration files of an application.

What is Inbound/Outbound Variant?

  • Inbound use of hard-coded credentials involves using hard-coded credentials to authenticate incoming requests or connections to the application.

    • For example, let's say you have a web application that requires users to enter a username and password to log in. In this scenario, if the application's source code contains hard-coded credentials that are used to authenticate the incoming user requests, it would be an example of inbound use of hard-coded credentials.

  • Outbound use of hard-coded credentials involves using hard-coded credentials to authenticate the application itself when it interacts with external systems or services.

    • For Example, consider a software application that needs to connect to a database for retrieving or storing data. If the application's code contains hard-coded credentials that are used to authenticate the application when establishing the connection to the database, it would be an example of outbound use of hard-coded credentials.

Impact

  • Unauthorized Access

  • Credential Exposure

  • Lack of Accountability

  • Difficulty in Credential Management

  • Compliance Violations

Example with Code Explanation:

  • Let us consider an example case and understand the CWE 798 with context of Vulnerable code and Mitigated code.

C

Vulnerable Code

#include <stdio.h>
#include <string.h>

void authenticate(char* username, char* password) {
    char validUsername[] = "admin";
    char validPassword[] = "password123";

    if (strcmp(username, validUsername) == 0 && strcmp(password, validPassword) == 0) {
        printf("Authentication successful.\n");
    } else {
        printf("Authentication failed.\n");
    }
}

int main() {
    char username[] = "admin";
    char password[] = "password123";

    authenticate(username, password);

    return 0;
}

In this code, the authenticate function compares the provided username and password with hard-coded credentials (validUsername and validPassword). If the comparison succeeds, it prints Authentication successful, indicating a successful login. Otherwise, it prints Authentication failed. This approach is vulnerable because the valid credentials are hard-coded directly into the source code. If an attacker gains access to the code, they can easily extract the credentials and potentially gain unauthorized access to the system.

Some of the ways the Vulnerable code can be mitigated is:

  • Use Credential Storage Mechanisms:Instead of hard-coding credentials directly in the code or configuration files, use secure storage mechanisms such as encrypted files, secure key stores, or dedicated credential management systems. This helps protect the credentials from unauthorized access and reduces the risk of exposure.

  • Externalize Credentials:Store credentials separately from the application code. Use external configuration files or environment variables to provide credentials at runtime. This separation allows for easier credential management, reduces the risk of accidental exposure, and facilitates secure deployment and configuration management.

  • Employ Encryption or Hashing:If credentials need to be stored within the application, consider using strong encryption or hashing algorithms to protect them. This adds an additional layer of security and makes it harder for attackers to extract the original credentials even if they gain access to the code.

  • Implement Credential Rotation:Regularly rotate credentials, especially for sensitive accounts or high-value systems. Periodic rotation of credentials reduces the window of opportunity for attackers and limits the potential impact of a compromised credential.

  • Use Token-based Authentication:Instead of using traditional username/password combinations, consider implementing token-based authentication mechanisms such as JSON Web Tokens (JWT) or OAuth. These mechanisms eliminate the need for hard-coded credentials and provide more secure and flexible authentication options.

  • Employ Secure Key Management:If using API keys, access tokens, or other forms of credentials, employ secure key management practices. This includes securely generating, distributing, and revoking keys, as well as implementing appropriate access controls and auditing mechanisms.

Mitigated Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

// Simulating retrieval of credentials from a secure configuration file or external source
void retrieveCredentials(char* username, char* password) {
    // Retrieve the credentials from a secure storage location or external service
    // For demonstration purposes, assume retrieval logic from a secure source
    
    // Example: Retrieval from an encrypted configuration file using SSL/TLS
    SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
    if (ctx == NULL) {
        printf("Error: Unable to create SSL context.\n");
        exit(1);
    }

    // Load the trust store
    if (!SSL_CTX_load_verify_locations(ctx, "truststore.pem", NULL)) {
        printf("Error: Unable to load trust store.\n");
        exit(1);
    }

    // Create an SSL connection
    BIO* bio = BIO_new_ssl_connect(ctx);
    if (bio == NULL) {
        printf("Error: Unable to create SSL connection.\n");
        exit(1);
    }

    // Connect to the configuration file server
    BIO_set_conn_hostname(bio, "config.example.com:443");

    // Verify the server certificate
    SSL* ssl;
    BIO_get_ssl(bio, &ssl);
    if (SSL_get_verify_result(ssl) != X509_V_OK) {
        printf("Error: Server certificate verification failed.\n");
        exit(1);
    }

    // Read the encrypted credentials from the configuration file
    char encryptedCredentials[64];
    int len = BIO_read(bio, encryptedCredentials, sizeof(encryptedCredentials));
    if (len <= 0) {
        printf("Error: Unable to read encrypted credentials.\n");
        exit(1);
    }

    // Decrypt the credentials using a symmetric key
    // For demonstration purposes, assume decryption logic using a symmetric key
    // ...

    // Parse the decrypted credentials into username and password
    if (sscanf(decryptedCredentials, "%s %s", username, password) != 2) {
        printf("Error: Invalid credential format.\n");
        exit(1);
    }

    // Free the SSL resources
    BIO_free_all(bio);
    SSL_CTX_free(ctx);
}

// Compare two strings in constant time to prevent timing attacks
int constant_time_compare(const char* a, const char* b) {
    size_t len_a = strlen(a);
    size_t len_b = strlen(b);

    if (len_a != len_b) {
        return 0;
    }

    unsigned char result = 0;
    for (size_t i = 0; i < len_a; i++) {
        result |= a[i] ^ b[i];
    }
    
    return result == 0;
}

void authenticate(char* username, char* password) {
    // Perform authentication logic
    // For demonstration purposes, compare with retrieved credentials
    char retrievedUsername[32];
    char retrievedPassword[32];
    
     // Retrieve the hashed password using the username as a key
     retrieveCredentials(retrievedUsername, retrievedPassword);

     // Hash the input password using the same algorithm and salt as the retrieved password
     char hashedPassword[32];
     EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
     if (mdctx == NULL) {
         printf("Error: Unable to create hash context.\n");
         exit(1);
     }

     if (!EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) {
         printf("Error: Unable to initialize hash function.\n");
         exit(1);
     }

     // Assume a fixed salt for demonstration purposes
     unsigned char salt[] = "1234567890abcdef";

     if (!EVP_DigestUpdate(mdctx, salt, sizeof(salt))) {
         printf("Error: Unable to update hash with salt.\n");
         exit(1);
     }

     if (!EVP_DigestUpdate(mdctx, password, strlen(password))) {
         printf("Error: Unable to update hash with password.\n");
         exit(1);
     }

     unsigned int len;
     unsigned char digest[EVP_MAX_MD_SIZE];
     if (!EVP_DigestFinal_ex(mdctx, digest, &len)) {
         printf("Error: Unable to finalize hash.\n");
         exit(1);
     }

     EVP_MD_CTX_free(mdctx);

     // Convert the digest to a hex string
     for (unsigned int i = 0; i < len; i++) {
         sprintf(hashedPassword + (i * 2), "%02x", digest[i]);
     }
     
     hashedPassword[len * 2] = '\0';

     // Compare the input username and hashed password with the retrieved ones in constant time
     if (constant_time_compare(username, retrievedUsername) && constant_time_compare(hashedPassword, retrievedPassword)) {
         printf("Authentication successful.\n");
     } else {
         printf("Authentication failed.\n");
     }
}

int main() {
   char username[32];
   char password[32];

   retrieveCredentials(username, password);

   authenticate(username, password);

   // Clear credentials from memory
   memset(username, 0, sizeof(username));
   memset(password, 0, sizeof(password));

   return 0;
}

The Mitigated code does the following:

  • Retrieval of credentials: The mitigated code simulates retrieving credentials from a secure configuration file or external source. It uses SSL/TLS to establish a secure connection, loads a trust store, verifies the server certificate, and reads the encrypted credentials from the configuration file. The actual retrieval logic may vary depending on the implementation.

  • Encryption and decryption: The mitigated code includes encryption and decryption mechanisms to protect the credentials stored in the configuration file. It assumes a symmetric key for decryption, although the actual implementation may use a more secure encryption scheme.

  • Hashing and constant-time comparison: The mitigated code hashes the input password using a cryptographic hash function (SHA-256) and a salt value. It then compares the hashed password and username with the retrieved values using a constant-time comparison function. This prevents attackers from exploiting timing attacks to gain information about the credentials.

  • Secure memory handling: The mitigated code clears the credentials from memory using memset after authentication to minimize the risk of the sensitive data being accessed by other processes or attackers.

Java

Vulnerable Code

  • The below Vulnerable and Mitgated code focuses on Inbound Authentication.

import java.util.Scanner;

public class VulnerableCode {

    // Simulating hard-coded default credentials for first time logins
    private static final String DEFAULT_USERNAME = "admin";
    private static final String DEFAULT_PASSWORD = "password123";

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // Assume credentials are obtained securely at runtime
        // For demonstration purposes, use hard-coded values
        String username = "admin";
        String password = "password123";

        authenticate(username, password);

        // Clear credentials from memory
        username = null;
        password = null;

        scanner.close();
    }

    public static void authenticate(String username, String password) {
        // Perform authentication logic
        // For demonstration purposes, compare with default credentials
        if (username.equals(DEFAULT_USERNAME) && password.equals(DEFAULT_PASSWORD)) {
            System.out.println("Authentication successful.");
        } else {
            System.out.println("Authentication failed.");
        }
    }
}

The code is Vulnerable, because it uses hard-coded default credentials for first time logins. The default username and password are stored in plain text in the DEFAULT_USERNAME and DEFAULT_PASSWORD constants and can be easily extracted by an attacker. This can allow an attacker to bypass the authentication mechanism and access the system.

  • Some of the ways the Vulnerable code can be mitigated is

  • For Inbound Authentication, Implement a "first login" mode: Instead of hard-coding default credentials, introduce a mechanism where users are required to enter a unique strong password or key during their initial login. This ensures that each user sets their own credentials. (as per CWE listed Potential Mitigations).

  • Use secure storage for credentials: Store the user's credentials in a secure manner, such as using cryptographic techniques to protect sensitive information. Avoid storing plaintext passwords or keys.

  • Implement multi-factor authentication (MFA): Consider implementing MFA, where users are required to provide additional verification factors (such as a one-time password or biometric data) along with their credentials. This adds an extra layer of security to the authentication process.

Mitigated Code

import java.util.Scanner;

public class MitigatedCode {

    // Simulating a "first login" mode that requires the user to enter a unique strong password
    private static boolean firstLogin = true; // A flag to indicate whether it is the first login or not
    private static String username; // A variable to store the user's username
    private static String password; // A variable to store the user's password

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        if (firstLogin) {
            System.out.println("Welcome to the system. Please enter a unique username and a strong password.");
            username = scanner.nextLine(); // Assume input validation and error handling
            password = scanner.nextLine(); // Assume input validation and error handling
            System.out.println("Thank you. Your credentials are saved.");
        } else {
            System.out.println("Please enter your username and password.");
            username = scanner.nextLine(); // Assume input validation and error handling
            password = scanner.nextLine(); // Assume input validation and error handling
        }

        authenticate(username, password);

        // Clear credentials from memory
        username = null;
        password = null;

        scanner.close();
    }

    public static void authenticate(String username, String password) {
        // Perform authentication logic
        // For demonstration purposes, compare with stored credentials
        if (username.equals(username) && password.equals(password)) {
            System.out.println("Authentication successful.");
            if (firstLogin) {
                System.out.println("Please change your password to a strong one.");
                firstLogin = false; // Reset the flag after the first login
            }
        } else {
            System.out.println("Authentication failed.");
        }
    }
}

The Mitigated code does the following:

  • The code demonstrates mitigation for CWE-798 by implementing a first login mode that requires the user to enter a unique strong password, for inbound Authentication.

Python

Vulnerable Code

import requests

# Hard-coded credentials
username = "admin"
password = "secret"

# Outbound communication to an external component
response = requests.get("https://example.com/api", auth=(username, password))

# Inbound authentication using passwords
def login(user, pwd):
    # Check the input credentials against a hard-coded set of credentials
    if user == username and pwd == password:
        return True
    else:
        return False

The above code is Vulnerable due to:

Hard-coded credentials: The username and password are directly embedded in the code, making them easily accessible to anyone who has access to the source code.

Outbound communication: The code sends the username and password as part of the HTTP request to the external API using the requests.get() function. This means that the credentials are transmitted over the network in plain text, which is highly insecure.

Inbound authentication: The login() function compares the input credentials directly with the hard-coded credentials.

The Vulnerable code can be mitigated by:

  • Store credentials in a secure configuration file or database with appropriate access control.

  • Apply strong one-way hash functions with random salts to passwords before storing them.

  • Use secure protocols such as HTTPS for transmitting sensitive information over the network.

  • Implement a secure authentication mechanism that compares the hashed input password with the stored hash, rather than comparing plain-text passwords directly.

Mitigated Code

import requests
import hashlib

# Load credentials from a secure configuration file or database
with open("config.txt", "r") as f:
    username, password_hash, salt = f.read().split()

# Outbound communication to an external component
response = requests.get("https://example.com/api", auth=(username, password_hash))

# Inbound authentication using passwords
def login(user, pwd):
    # Apply strong one-way hash with salt to the incoming password
    pwd_hash = hashlib.sha256((pwd + salt).encode()).hexdigest()
    # Compare the hashed password with the stored hash
    if user == username and pwd_hash == password_hash:
        return True
    else:
        return False

The Mitigated code does the following:

  • It applies a strong one-way hash with a salt to the incoming password during authentication.

  • The secure loading of credentials from a configuration file or database. It reads the username, password hash, and salt from the "config.txt" file, assuming they are stored securely.

References

Use of hard-coded password | OWASP Foundation

A07 Identification and Authentication Failures - OWASP Top 10:2021

How to Prevent Hardcoded Passwords?

GO Code Review #1 : Hard-coded credentials are security-sensitive

Last updated

Was this helpful?