Skip to content

CWE-676: Use of Potentially Dangerous Function

Overview

Dangerous functions (strcpy, gets, system, eval, exec) lack bounds checking, enable code execution, or have inherent security flaws. Using them creates buffer overflows, command injection, code injection, and other vulnerabilities that modern alternatives prevent.

OWASP Classification

A06:2025 - Insecure Design

Risk

High: Dangerous functions cause buffer overflows (strcpy, gets), command injection (system, exec), code injection (eval), race conditions (access), and predictable randomness (rand), with exploits well-documented and widely used in attacks.

Remediation Strategy

Replace Unsafe String Functions (Primary Defense)

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

// SAFE - bounds-checked alternatives
strncpy(dest, user_input, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';

fgets(dest, sizeof(dest), stdin);  // Safe

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

strlcpy(dest, input, sizeof(dest));  // BSD

Replace Command Execution Functions

# DANGEROUS - command injection

import os
filename = request.args.get('file')
os.system(f'cat {filename}')  // Injection!

# Attacker: file=file.txt; rm -rf /

# SAFE - use subprocess with array

import subprocess
result = subprocess.run(
    ['cat', filename],  # Arguments as array
    capture_output=True,
    text=True,
    check=True
)

Replace Dynamic Code Execution

# DANGEROUS

code = request.form['code']
eval(code)  # Remote code execution!
exec(code)  # Remote code execution!

# SAFE - use safe alternatives

# For math expressions

import ast
import operator

safe_ops = {
    ast.Add: operator.add,
    ast.Sub: operator.sub,
    ast.Mult: operator.mul,
    ast.Div: operator.truediv
}

def safe_eval(expr):
    tree = ast.parse(expr, mode='eval')
    # Validate only safe operations
    return eval_tree(tree.body, safe_ops)

Replace Weak Random Functions

// DANGEROUS - predictable
srand(time(NULL));
int token = rand();  // NOT cryptographically secure

// SAFE - cryptographic random
#include <openssl/rand.h>
unsigned char token[32];
RAND_bytes(token, sizeof(token));

// Or /dev/urandom on Unix
int fd = open("/dev/urandom", O_RDONLY);
read(fd, token, sizeof(token));
close(fd);

Remediation Steps

Core principle: Ban inherently dangerous functions in security-sensitive code; enforce via tooling and code review.

  1. Identify dangerous function calls
  2. Determine the risk
  3. Locate data flow to dangerous function
  4. Replace with safe alternatives: Use bounds-checked functions (strncpy, snprintf), parameterized execution (subprocess with arrays), crypto random (RAND_bytes)
  5. Add validation where replacement isn't possible: If dangerous function must be used, add strict input validation and bounds checking
  6. Test with attack payloads: Try buffer overflows, command injection, code injection to verify safe replacement blocks attacks
  7. Grep codebase for other dangerous functions: Search for all instances and replace systematically

Dangerous Functions and Replacements

C String Functions:

  • strcpy() → strncpy(), strlcpy(), strcpy_s()
  • strcat() → strncat(), strlcat()
  • gets() → fgets()
  • sprintf() → snprintf()
  • scanf("%s") → scanf("%99s") or fgets()

Command Execution:

  • system() → execve() with sanitized args
  • popen() → fork()+exec() with pipes
  • exec() (Python) → Don't use with user input
  • eval() → JSON parsing, safe expression evaluators

File Operations:

  • access() → open() (avoids TOCTOU)
  • tmpnam() → mkstemp()
  • tempnam() → mkstemp()

Random:

  • rand(), random() → /dev/urandom, RAND_bytes()
  • Math.random() (JS) → crypto.getRandomValues()
  • Random() (Python) → secrets module

Memory:

  • alloca() → malloc() or VLA
  • realpath() → Check return value

Examples of Vulnerable Code

// Buffer overflow
void process_name(char *name) {
    char buffer[64];
    strcpy(buffer, name);  // Overflow if name > 63 chars
    printf("%s\n", buffer);
}

// Command injection
void backup_file(char *filename) {
    char cmd[256];
    sprintf(cmd, "cp %s %s.bak", filename, filename);
    system(cmd);  // Shell interprets special chars!
}

// Code injection
void calculate(char *expression) {
    eval(expression);  // Arbitrary code execution!
}

Secure Alternatives

// Bounded string copy
void process_name_safe(const char *name) {
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "%s", name);
    printf("%s\n", buffer);
}

// Safe command execution
void backup_file_safe(const char *filename) {
    pid_t pid = fork();
    if (pid == 0) {
        // Child process
        char *args[] = {"cp", filename, 
                       generate_backup_name(filename), NULL};
        execvp("cp", args);
        _exit(1);
    }
    waitpid(pid, NULL, 0);
}
# Safe expression evaluation

import ast

class SafeEvaluator(ast.NodeVisitor):
    def visit(self, node):
        if not isinstance(node, (ast.Expression, ast.Num, 
                                 ast.BinOp, ast.Add, ast.Sub)):
            raise ValueError("Unsafe operation")
        return super().visit(node)

def safe_eval(expr):
    tree = ast.parse(expr, mode='eval')
    SafeEvaluator().visit(tree)
    return eval(compile(tree, '<string>', 'eval'))

Additional Resources