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/strlcaton BSD systems (OpenBSD, macOS) - Use
strncpy/strncaton Linux (but manually ensure null termination) - Use
strcpy_s/strcat_son 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:
- Dynamic Scan Guidance - Analyzing DAST findings and mapping to source code