Skip to content

CWE-477: Use of Obsolete Function

Overview

Obsolete functions are deprecated due to security vulnerabilities, lack of bounds checking, or design flaws. Using strcpy, gets, rand, MD5, DES exposes applications to buffer overflows, weak randomness, and broken cryptography that modern replacements fix.

Risk

Medium-High: Obsolete functions cause buffer overflows (strcpy, gets), weak randomness (rand), broken crypto (MD5, DES), race conditions (tmpnam), and known vulnerabilities. Modern alternatives provide security guarantees missing from legacy functions.

Remediation Steps

Core principle: Never rely on deprecated or obsolete APIs for security-relevant behavior; application design must restrict implementation to supported, maintained functions with known security properties.

Locate the Obsolete Function Usage

When reviewing security scan results:

  • Examine data_paths: Identify which obsolete functions are being used
  • Categorize by risk: String functions (buffer overflow), crypto (broken), random (predictable)
  • Find all occurrences: Use grep/search to find all uses of the obsolete function
  • Assess impact: Determine if function is in security-critical code path
  • Check for alternatives: Identify which modern replacement is appropriate

Common obsolete functions to look for:

  • String: strcpy, strcat, gets, sprintf
  • Crypto: MD5, SHA-1, DES, RC4
  • Random: rand, srand, random
  • File: tmpnam, tempnam

Replace Unsafe String Functions with Bounds-Checked Alternatives

// UNSAFE - no bounds checking
char buf[10];
strcpy(buf, input);  // Buffer overflow!
gets(buf);           // Extremely dangerous
strcat(dest, src);   // No bounds check
sprintf(buf, "%s", input);  // No bounds check

// SAFE - bounds-checked alternatives
strncpy(buf, input, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';  // Ensure null termination

fgets(buf, sizeof(buf), stdin);  // Safe, includes size

strlcpy(buf, input, sizeof(buf));  // BSD, automatically null-terminates
strlcat(dest, src, sizeof(dest));  // BSD

snprintf(buf, sizeof(buf), "%s", input);  // Safe, bounded

Why this works: Modern string functions accept a size parameter and guarantee null termination, preventing buffer overflows that strcpy/strcat/gets allow.

Platform-specific notes:

  • Use strlcpy/strlcat on BSD systems (OpenBSD, macOS)
  • Use strncpy/strncat on Linux (but manually ensure null termination)
  • Use strcpy_s/strcat_s on Windows (C11 Annex K)

Use Modern Cryptography Algorithms

# OBSOLETE - broken crypto
import md5  # Deprecated, collision attacks
hash = md5.new(data).hexdigest()

import hashlib
hash = hashlib.sha1(data).hexdigest()  # Also deprecated

# MODERN - strong hashing
import hashlib
hash = hashlib.sha256(data).hexdigest()  # Good for general use
hash = hashlib.sha3_256(data).hexdigest()  # SHA-3 family

# For passwords - use password hashing, not general hashing
import bcrypt
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))

# Or use argon2
from argon2 import PasswordHasher
ph = PasswordHasher()
hashed = ph.hash(password)

Cryptography replacements:

  • MD5 → SHA-256, SHA-3 (or bcrypt/argon2 for passwords)
  • SHA-1 → SHA-256 or higher
  • DES → AES-256
  • 3DES → AES-256
  • RC4 → ChaCha20, AES-GCM

Use Cryptographically Secure Random Generators

// OBSOLETE - predictable, not cryptographically secure
srand(time(NULL));  // Predictable seed
int token = rand();  // NOT secure for security purposes
int sessionId = rand() % 1000000;

// MODERN - cryptographically secure random
#include <openssl/rand.h>
unsigned char token[32];
if (RAND_bytes(token, sizeof(token)) != 1) {
    // Error handling
}

// Or use /dev/urandom on Unix
int fd = open("/dev/urandom", O_RDONLY);
read(fd, token, sizeof(token));
close(fd);
# OBSOLETE - predictable
import random
random.seed()
token = random.randint(0, 1000000)  # Predictable

# MODERN - cryptographically secure
import secrets
token = secrets.token_bytes(32)  # Random bytes
token_hex = secrets.token_hex(16)  # Random hex string
token_url = secrets.token_urlsafe(32)  # URL-safe token

Why this matters: rand() is predictable and should never be used for security tokens, session IDs, cryptographic keys, or passwords.

Replace Temporary File Functions with Secure Alternatives

// OBSOLETE - race condition, predictable name
char *filename = tmpnam(NULL);  // Predictable, TOCTOU
FILE *f = fopen(filename, "w");  // Race condition

char *filename = tempnam("/tmp", "prefix");  // Also unsafe

// MODERN - secure temp file creation
#include <stdlib.h>
char template[] = "/tmp/myapp.XXXXXX";
int fd = mkstemp(template);  // Creates file atomically, mode 0600
if (fd == -1) {
    perror("mkstemp");
}
FILE *f = fdopen(fd, "w");
// Use f...
fclose(f);  // Also closes fd
unlink(template);  // Remove file

Why mkstemp is better:

  • Creates file atomically (no TOCTOU race)
  • Unpredictable filename
  • Restrictive permissions (0600)
  • Returns file descriptor (not just name)

Test and Verify the Replacement

Testing approach:

  • Ensure new functions handle all input sizes correctly
  • Test with buffer sizes: 0, 1, boundary conditions, large values
  • For crypto: verify hashes match expected format and length
  • For random: verify output is unpredictable (statistical tests)
  • For strings: test that buffer overflows are prevented

String function tests:

// Test boundary conditions
char small[5];
strncpy(small, "test", sizeof(small) - 1);
small[sizeof(small) - 1] = '\0';
assert(strlen(small) == 4);

// Test overflow prevention
strncpy(small, "this is too long", sizeof(small) - 1);
small[sizeof(small) - 1] = '\0';
assert(strlen(small) == 4);  // Truncated safely

Verification steps:

  • Run with AddressSanitizer to detect buffer overflows: gcc -fsanitize=address
  • Use static analysis tools to find remaining obsolete functions
  • Review cryptographic usage with security team
  • Test random number generator with statistical tests (dieharder, NIST suite)

Complete replacement checklist:

  • All strcpy → strncpy/strlcpy/strcpy_s
  • All strcat → strncat/strlcat
  • All gets → fgets
  • All sprintf → snprintf
  • All MD5/SHA-1 → SHA-256+
  • All DES/3DES/RC4 → AES-256/ChaCha20
  • All rand → RAND_bytes/secrets
  • All tmpnam → mkstemp

Common Obsolete Functions and Replacements

C String Functions:

  • strcpy → strncpy, strlcpy, strcpy_s
  • strcat → strncat, strlcat
  • gets → fgets
  • sprintf → snprintf

Crypto:

  • MD5 → SHA-256, SHA-3
  • SHA-1 → SHA-256+
  • DES → AES
  • RC4 → ChaCha20

Random:

  • rand() → RAND_bytes(), arc4random()
  • random() → secrets module (Python)

File/Temp:

  • tmpnam → mkstemp
  • tempnam → mkstemp

Other:

  • getwd() → getcwd()
  • bcopy() → memcpy()
  • bzero() → memset()

Dynamic Scan Guidance

For guidance on remediating this CWE when detected by dynamic (DAST) scanners:

Additional Resources