Skip to content

Semgrep c, cpp rules


c_buffer_rule-gets--getts

Summary:

Use of deprecated function (gets)

Severity: High

CWE: CWE-120

Description:

The gets() function (and its wide-character variants _getts() and _getws()) reads a line from stdin into the provided buffer until either a terminating newline or EOF is encountered, replacing it with a null byte. These functions perform no bounds checking on the destination buffer, making buffer overflow attacks trivial to execute. The gets() function was officially removed from the C11 standard due to its inherent security risks and inability to be used safely under any circumstances.

Remediation:

Consider replacing gets() with fgets() which accepts a maximum buffer size parameter to prevent overflows. The fgets() function should be called with the buffer size as the second parameter, for example fgets(buffer, sizeof(buffer), stdin). Note that fgets() retains the newline character if the buffer is large enough, so you may need to strip it manually. For reading binary data or inputs that may contain null bytes, use read() or fread() instead, as fgets() stops at the first null byte on some platforms. For new C code, consider using safer alternatives like getline() on POSIX systems which automatically manages buffer allocation.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_buffer_rule-getwd

Summary:

Insufficient protection against buffer overflow (getwd)

Severity: High

CWE: CWE-120

Description:

The getwd() function retrieves the current working directory path but does not accept a size parameter to limit how many characters can be written to the destination buffer. This creates a buffer overflow vulnerability when the path exceeds the buffer size, particularly on systems with deep directory structures. The function has been deprecated from POSIX standards and removed from modern C libraries due to these security concerns.

Remediation:

Consider migrating to getcwd() which accepts both a buffer pointer and a size parameter to safely limit the number of characters written. The standard usage is getcwd(buffer, sizeof(buffer)) which ensures the path is truncated if it exceeds the buffer size. For maximum portability, recommended to allocate at least PATH_MAX bytes for the buffer, though on some systems you can pass NULL as the buffer parameter to have getcwd() allocate memory automatically (must be freed with free()). The getcwd() function will return NULL and set errno to ERANGE if the buffer is too small, allowing for graceful error handling.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_buffer_rule-scanf-vscanf

Summary:

scanf() functions may allow format string based overflows

Severity: High

CWE: CWE-120

Description:

The scanf(), vscanf(), wscanf(), _tscanf(), and vwscanf() family of functions can cause buffer overflows when format specifiers like %s are used without field width limitations. When reading string data without a width specifier, these functions will continue writing to the destination buffer until whitespace is encountered or EOF is reached, regardless of the buffer's actual size. This makes them particularly dangerous when processing untrusted input where an attacker can provide arbitrarily long strings to overflow buffers and potentially execute arbitrary code.

Remediation:

Consider using field width specifiers in all string format specifiers to limit buffer writes, for example scanf("%10s", buffer) will read at most 10 characters plus a null terminator into an 11-byte buffer. Recommended to calculate the width as sizeof(buffer)-1 to leave room for the null terminator. For Microsoft C Runtime Library (CRT) development, use the _s suffixed secure versions like scanf_s() which require explicit buffer sizes and provide runtime bounds checking. For more robust input handling, consider using fgets() followed by sscanf() which allows you to control the input line length separately from parsing, or use getline() on POSIX systems for automatic buffer management.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_format_rule-fprintf-vfprintf

Summary:

Potential format string vulnerability

Severity: High

CWE: CWE-134

Description:

The application uses fprintf(), vfprintf(), _ftprintf(), fwprintf(), or fvwprintf() with a non-constant format string argument. Format string vulnerabilities allow an attacker to read or in some cases potentially write data to and from locations in the process memory. When user-controlled or untrusted input is passed directly as the format specification to these functions, attackers can use format specifiers like %x, %n, and %s to leak sensitive information from the stack or write arbitrary data to memory locations.

Remediation:

Consider using a constant string literal for the format specification instead of accepting user-controlled or untrusted input. If dynamic format strings are required, recommended to implement strict validation that only allows specific safe characters and completely strips out format specifiers like %x, %n, %s, and %p. For logging user-provided data, consider using safe alternatives like fputs() which does not interpret format specifiers. When calling fprintf() or related functions, always use a fixed format string such as fprintf(fd, "%s", user_data) rather than fprintf(fd, user_data). The compiler flag -Wformat-security can help detect cases where non-literal format strings are used without proper arguments.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_format_rule-printf-vprintf

Summary:

Potential format string vulnerability

Severity: High

CWE: CWE-134

Description:

The application uses printf(), vprintf(), vwprintf(), vfwprintf(), _vtprintf(), or wprintf() with a non-constant format string argument. Format string vulnerabilities allow an attacker to read or in some cases potentially write data to and from locations in the process memory. When user-controlled or untrusted input is passed directly as the format specification to these functions, attackers can use format specifiers like %x, %n, and %s to leak sensitive information from the stack or write arbitrary data to memory locations.

Remediation:

Consider using a constant string literal for the format specification instead of accepting user-controlled or untrusted input. If dynamic format strings are required, recommended to implement strict validation that only allows specific safe characters and completely strips out format specifiers like %x, %n, %s, and %p. For printing user-provided data, consider using safe alternatives like puts() which does not interpret format specifiers. When calling printf() or related functions, always use a fixed format string such as printf("%s", user_data) rather than printf(user_data). The compiler flag -Wformat-security can help detect cases where non-literal format strings are used without proper arguments.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_format_rule-snprintf-vsnprintf

Summary:

Potential format string vulnerability

Severity: High

CWE: CWE-134

Description:

The application uses snprintf(), vsnprintf(), _snprintf(), _sntprintf(), or _vsntprintf() with a non-constant format string argument. Format string vulnerabilities allow an attacker to read or in some cases potentially write data to and from locations in the process memory. When user-controlled or untrusted input is passed directly as the format specification to these functions, attackers can use format specifiers like %x, %n, and %s to leak sensitive information from the stack or write arbitrary data to memory locations. Note that some variations of these functions do not always null-terminate the resulting strings.

Remediation:

Consider using a constant string literal for the format specification instead of accepting user-controlled or untrusted input. If dynamic format strings are required, recommended to implement strict validation that only allows specific safe characters and completely strips out format specifiers like %x, %n, %s, and %p. For copying user-provided data into a buffer, consider using safer alternatives like strncpy() or strlcpy() which do not interpret format specifiers. When calling snprintf() or related functions, always use a fixed format string such as snprintf(buf, size, "%s", user_data) rather than snprintf(buf, size, user_data). Be aware that _snprintf() does not guarantee null-termination when the buffer is too small, so consider using the standard snprintf() where available. The compiler flag -Wformat-security can help detect cases where non-literal format strings are used without proper arguments.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_format_rule-syslog

Summary:

Potential format string vulnerability in syslog call

Severity: High

CWE: CWE-134

Description:

The application uses syslog() with a non-constant format string argument. Format string vulnerabilities allow an attacker to read or in some cases potentially write data to and from locations in the process memory. When user-controlled or untrusted input is passed directly as the format specification to syslog(), attackers can use format specifiers like %x, %n, and %s to leak sensitive information from the stack or write arbitrary data to memory locations. This is particularly dangerous in syslog() because it is commonly used to log user-provided input, making it a frequent target for format string attacks.

Remediation:

Consider using a constant string literal for the format specification instead of accepting user-controlled or untrusted input. Recommended to always call syslog() with a fixed format string such as syslog(priority, "%s", user_data) rather than syslog(priority, user_data). If you need to log user-provided messages, consider implementing strict validation that completely strips out format specifiers like %x, %n, %s, and %p before passing data to syslog(). For additional safety, consider using syslog wrappers that automatically sanitize input or use structured logging libraries that separate the log message template from the data being logged. The compiler flag -Wformat-security can help detect cases where non-literal format strings are used without proper arguments.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_shell_rule-CreateProcess

Summary:

Possible executable path hijacking (CreateProcess)

Severity: High

CWE: CWE-78

Description:

The CreateProcess() Windows API function is vulnerable to executable path hijacking due to how it parses spaces in unquoted paths. When paths contain spaces and are not properly quoted, an attacker may exploit this by placing a malicious binary earlier in the search path that matches the first part of the intended executable name. This vulnerability is particularly dangerous in directories like 'C:\Program Files' where spaces are common in legitimate paths.

Remediation:

Consider always enclosing the executable path in escaped quotation marks to prevent path hijacking vulnerabilities. For example, use CreateProcessA(NULL, "\"C:\Program Files\MyApp.exe\"", ...) to ensure the entire path is treated as a single argument. It is recommended to specify the full absolute path to the executable rather than relying on PATH environment variable resolution. Additionally, consider validating that the executable exists at the expected location before calling CreateProcess() and checking its digital signature when dealing with security-sensitive operations. For more detailed guidance, see Microsoft's security remarks at https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa#security-remarks

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_shell_rule-CreateProcessAsUser-CreateProcessWithLogon

Summary:

Possible executable path hijacking (CreateProcessAsUser/CreateProcessWithLogon)

Severity: High

CWE: CWE-78

Description:

The CreateProcessAsUser() and CreateProcessWithLogon() Windows API functions are vulnerable to executable path hijacking due to how they parse spaces in unquoted paths. When paths contain spaces and are not properly quoted, an attacker may exploit this by placing a malicious binary earlier in the search path that matches the first part of the intended executable name. These functions are particularly concerning because they run processes under different security contexts, making path hijacking attacks even more dangerous as the malicious code would execute with the elevated or alternate user's privileges.

Remediation:

Consider always enclosing the executable path in escaped quotation marks to prevent path hijacking vulnerabilities. For CreateProcessAsUser(), use the format CreateProcessAsUser(hToken, NULL, "\"C:\Program Files\MyApp.exe\"", ...) to ensure the entire path is treated as a single argument. It is recommended to specify the full absolute path to the executable and validate that it exists at the expected location before execution. Given that these functions execute code under different security contexts, consider additionally verifying the executable's digital signature to ensure authenticity. For CreateProcessWithLogon(), the same quoting rules apply but be aware that credentials are passed in plaintext and consider using CreateProcessWithTokenW() instead for better security. See Microsoft's documentation at https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasusera#security-remarks for detailed security guidance.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_shell_rule-execl-execlp

Summary:

Potential for OS command injection

Severity: High

CWE: CWE-78

Description:

The application uses C/C++ command execution functions including execl(), execlp(), execle(), execv(), execvp(), popen(), or Windows APIs WinExec() and ShellExecute() which can lead to OS command injection vulnerabilities. These functions are particularly dangerous when any part of the command string or arguments is constructed from user input, as attackers can inject arbitrary commands through shell metacharacters. The 'p' variants (execlp(), execvp()) are especially risky as they search PATH for executables, potentially allowing attackers to control which binary gets executed through PATH manipulation.

Remediation:

Consider replacing command execution with direct library calls that provide the same functionality without invoking a shell. If command execution is unavoidable, use the non-PATH-searching variants (execv() instead of execvp()) with hardcoded absolute paths to executables. Recommended to construct argument arrays programmatically rather than building command strings, as this prevents shell interpretation of metacharacters. When user input must be included in arguments, implement strict allowlisting of permitted values rather than attempting to sanitize or escape special characters. For Windows applications, prefer CreateProcess() with proper quoting over WinExec() or ShellExecute(), as it provides more control and doesn't invoke cmd.exe. See SEI CERT's compliant solutions at https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152177 for secure implementation patterns.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_shell_rule-system

Summary:

Potential for OS command injection

Severity: High

CWE: CWE-78

Description:

The application uses the system() C standard library function which invokes the system shell to execute commands, creating a significant OS command injection risk. The system() function is particularly dangerous because it passes the entire command string to the shell (typically /bin/sh on Unix or cmd.exe on Windows), allowing shell metacharacters like semicolons, pipes, and backticks to inject arbitrary commands. Even seemingly safe static commands can be exploited if environment variables or the PATH are under attacker control.

Remediation:

Consider replacing system() calls with direct library functions that provide equivalent functionality without shell invocation. If command execution is necessary, use fork() and execve() directly on Unix-like systems, or CreateProcess() on Windows, as these allow passing arguments as arrays rather than shell-interpreted strings. Recommended to use absolute paths to executables rather than relying on PATH resolution. When user input must influence command behavior, implement strict allowlisting of permitted values and construct argument arrays programmatically to prevent shell metacharacter interpretation. Never attempt to sanitize input by blacklisting special characters, as this approach is error-prone and bypassable. See SEI CERT C Coding Standard at https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152177 for detailed secure alternatives and implementation examples.

OWASP:

  • A1:2017-Injection
  • A03:2021-Injection

c_crypto_rule-EVP-des-ecb-EVP-des-cbc

Summary:

Insecure encryption algorithm (DES)

Severity: Medium

CWE: CWE-327

Description:

The application uses OpenSSL DES cipher functions such as EVP_des_ecb(), EVP_des_cbc(), EVP_des_cfb(), EVP_des_ofb(), or EVP_desx_cbc() which implement the Data Encryption Standard algorithm. DES has an effective key size of only 56 bits making it vulnerable to brute-force attacks with modern hardware. The algorithm was officially withdrawn from NIST (FIPS 46-3) in 2005 and has not been recommended for over 15 years.

Remediation:

Consider migrating to libsodium's crypto_secretbox_easy() or crypto_secretbox_detached() functions which provide authenticated encryption using XSalsa20 and Poly1305. These modern primitives are faster and significantly more secure than DES, protecting against both tampering and key recovery attacks. For applications requiring FIPS 140-2 compliance, recommended to use OpenSSL's AES cipher functions such as EVP_aes_256_gcm() for authenticated encryption or EVP_aes_256_cbc() with separate HMAC authentication. Avoid 3DES (EVP_des_ede3_cbc()) as it has a 64-bit block size making it vulnerable to birthday attacks after processing 32GB of data. For detailed libsodium usage examples, refer to https://libsodium.gitbook.io/doc/secret-key_cryptography/secretbox.

OWASP:

  • A3:2017-Sensitive Data Exposure
  • A02:2021-Cryptographic Failures

c_crypto_rule-EVP-rc4-40-EVP-rc2-40-cbc

Summary:

Insecure stream cipher (RC4)

Severity: Medium

CWE: CWE-327

Description:

The application uses OpenSSL RC4 or RC2 cipher functions such as EVP_rc4_40(), EVP_rc2_40_cbc(), or EVP_rc2_64_cbc() which implement broken stream ciphers. RC4 has multiple statistical biases in its keystream making it vulnerable to practical plaintext recovery attacks, particularly in protocols like TLS where the same key encrypts multiple messages. The 40-bit and 64-bit export-grade variants are additionally vulnerable to brute-force key recovery. RC4 was prohibited from use in TLS by RFC 7465 in 2015.

Remediation:

Consider using libsodium's crypto_secretstream_xchacha20poly1305_init_push() and crypto_secretstream_xchacha20poly1305_push() functions for stream cipher encryption with authentication. This modern construction protects against both tampering and key recovery while providing excellent performance on all platforms. For applications that need to maintain compatibility with existing RC4 deployments during migration, recommended to implement dual-mode operation where new connections use ChaCha20-Poly1305 while legacy connections are gradually phased out. If FIPS 140-2 compliance is required, can use OpenSSL's EVP_aes_256_ctr() in counter mode with separate HMAC-SHA256 authentication, though authenticated encryption modes like EVP_aes_256_gcm() are preferred. Avoid 3DES as a replacement due to its 64-bit block size vulnerability. For detailed libsodium stream encryption examples, refer to https://libsodium.gitbook.io/doc/secret-key_cryptography/secretstream.

OWASP:

  • A3:2017-Sensitive Data Exposure
  • A02:2021-Cryptographic Failures

c_crypto_rule-crypt-crypt-r

Summary:

Insecure hashing algorithm

Severity: Medium

CWE: CWE-327

Description:

The application uses the crypt() or crypt_r() functions from the POSIX crypt library for password hashing. These functions traditionally implement DES-based password hashing with a maximum effective password length of 8 characters and only 4096 possible salts, resulting in an extremely small key space. Even with extended implementations supporting MD5-based or SHA-256/SHA-512-based hashing, the crypt functions provide insufficient iteration counts by default making them vulnerable to GPU-accelerated brute-force attacks with modern hardware.

Remediation:

Consider migrating to libsodium's crypto_pwhash_str() and crypto_pwhash_str_verify() functions which implement the Argon2id password hashing algorithm. Argon2id is the winner of the Password Hashing Competition and provides strong resistance against both GPU and ASIC-based cracking attempts through memory-hard operations. The libsodium implementation automatically handles salt generation and parameter selection, making it significantly easier to use securely than manual bcrypt or PBKDF2 implementations. For interactive login use cases, recommended to use crypto_pwhash_OPSLIMIT_INTERACTIVE and crypto_pwhash_MEMLIMIT_INTERACTIVE constants for faster verification, while sensitive applications should use crypto_pwhash_OPSLIMIT_SENSITIVE and crypto_pwhash_MEMLIMIT_SENSITIVE for maximum security. For detailed password hashing examples and migration guidance, refer to https://libsodium.gitbook.io/doc/password_hashing.

OWASP:

  • A3:2017-Sensitive Data Exposure
  • A02:2021-Cryptographic Failures

c_tmpfile_rule-mktemp

Summary:

Use of deprecated function (mktemp)

Severity: Medium

CWE: CWE-377

Description:

The mktemp() function is deprecated and should no longer be used due to multiple security flaws. Some implementations create temporary filenames using predictable information such as the process ID and a single letter, making it trivial for attackers to guess the generated pathname. This creates a race condition vulnerability where an attacker could create or manipulate the file between the time mktemp() generates the name and when the application uses it, potentially leading to unauthorized file access, data corruption, or symlink attacks.

Remediation:

Consider migrating to the mkstemp() function, which creates and opens the temporary file atomically, eliminating the race condition window. However, recommended to be aware that mkstemp() also has security considerations. Ensure the process calls umask() with restrictive permissions (e.g., umask(0077)) before calling mkstemp() to prevent the file from being created with overly permissive access rights. After mkstemp() returns a file descriptor, validate the file permissions using fstat() before writing sensitive data. For more information on secure temporary file handling, refer to: viewpage.action

OWASP:

  • A5:2017-Broken Access Control
  • A01:2021-Broken Access Control

c_tmpfile_rule-tmpnam-tempnam

Summary:

Potential time of check time of use vulnerability (tmpnam/tempnam)

Severity: Medium

CWE: CWE-377

Description:

The tmpnam() and tempnam() functions are vulnerable to race condition attacks (time-of-check time-of-use). Between the time these functions return a pathname and when the application opens it, an attacker could create that pathname using open(), potentially hijacking the file handle, or create it as a symbolic link to redirect writes to an arbitrary location. This can lead to unauthorized file access, privilege escalation, or data corruption as the application unknowingly operates on attacker-controlled files.

Remediation:

Consider replacing tmpnam() and tempnam() with mkstemp(), which atomically creates and opens the temporary file in a single operation, eliminating the race condition window. Recommended to call umask() with restrictive permissions (e.g., umask(0077)) before invoking mkstemp() to ensure the temporary file is created with secure access controls that prevent other users from reading or modifying it. After obtaining the file descriptor from mkstemp(), validate the file permissions using fstat() before performing any sensitive operations. For comprehensive guidance on secure temporary file handling, refer to: viewpage.action

OWASP:

  • A5:2017-Broken Access Control
  • A01:2021-Broken Access Control