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