Rules
130 rules. The severity shown is the rule's default; an individual finding can be raised or lowered by context, such as the SAPI, the profile or a related setting.
Code execution #
EXEC-001Remote file inclusion enabledcritical
allow_url_include lets include/require load code from http://, ftp:// and data:// URLs, turning any file-inclusion bug into remote code execution.
Directives allow_url_include, allow_url_fopen
Fix: Set allow_url_include = Off. The directive has been deprecated since PHP 7.4.
EXEC-002Remote URLs accepted by file functionsmedium
allow_url_fopen lets fopen(), file_get_contents(), getimagesize() and friends fetch http:// and ftp:// URLs, which turns user-controlled paths into server-side request forgery.
Directives allow_url_fopen
Fix: Set allow_url_fopen = Off and use an HTTP client (cURL) with explicit allow-lists where remote fetches are needed.
EXEC-003Auto-prepended/appended file loaded through a stream wrappercritical
auto_prepend_file/auto_append_file pointing at php://input, data:, http:// or another wrapper executes request- or network-supplied code on every request; this is a classic FastCGI exploitation payload.
Directives auto_prepend_file, auto_append_file
Fix: Remove the directive or point it at a root-owned local file.
EXEC-004Code automatically prepended or appended to every scriptinfo
auto_prepend_file/auto_append_file run a file before/after every script. Security plugins use it legitimately, but a value set from .user.ini or .htaccess is a common web-shell persistence technique.
Directives auto_prepend_file, auto_append_file
Fix: Confirm the file is expected, root-owned and not writable by the PHP user; set user_ini.filename = to stop per-directory overrides if they are not needed.
EXEC-005Command execution functions are availablemedium
Functions that spawn processes turn code injection, deserialization gadgets and file uploads into full operating-system command execution.
Directives disable_functions
Fix: List the functions the application does not use in disable_functions (php.ini or php_admin_value in the FPM pool). Composer and symfony/process need proc_open.
EXEC-006disable_functions can be bypassedmedium
With every exec-style function disabled, putenv() combined with a function that launches sendmail lets an attacker set LD_PRELOAD and run native code anyway.
Directives disable_functions
Fix: Also disable putenv and the mail launchers that are not needed, or run PHP with a seccomp/AppArmor profile instead of relying on disable_functions.
EXEC-007FFI available to every scripthigh
ffi.enable = On lets any script call arbitrary C functions, which bypasses disable_functions, open_basedir and every other PHP-level restriction.
Directives ffi.enable
Fix: Use ffi.enable = preload (the default) so that only preloaded code can use FFI.
EXEC-008Runtime extension loading (dl) enabledlow
enable_dl permits dl() to load shared objects at runtime. dl() is only available to the CLI and embed SAPIs, so the impact is limited to scripts run from the command line.
Directives enable_dl
Fix: Set enable_dl = Off.
EXEC-009Phar archives writable at runtimemedium
phar.readonly = Off allows scripts to create and modify Phar archives, which helps attackers craft polyglot files for phar:// deserialization and code execution.
Directives phar.readonly
Fix: Set phar.readonly = On except on build machines.
EXEC-010Unsigned Phar archives acceptedlow
phar.require_hash = Off lets PHP open Phar archives without a signature.
Directives phar.require_hash
Fix: Set phar.require_hash = On.
EXEC-011Query string exposed as $argv in web requestsmedium
register_argc_argv = On fills $argv from the query string in web requests. Combined with a local file inclusion this enables the pearcmd.php remote-code-execution technique; it is On by default when no php.ini is loaded (e.g. official Docker images).
Directives register_argc_argv
Fix: Set register_argc_argv = Off for web SAPIs.
EXEC-012imap_open() may run rsh/ssh commandshigh
imap.enable_insecure_rsh lets imap_open() mailbox names inject arguments into rsh/ssh (CVE-2018-19518).
Directives imap.enable_insecure_rsh
Fix: Set imap.enable_insecure_rsh = Off.
EXEC-013Dangerous sendmail options configuredhigh
sendmail options such as -X (log file), -O/-C (alternate queue/config) or Exim's -be (expansion test) let mail() write attacker-influenced files or evaluate expressions.
Directives sendmail_path, mail.force_extra_parameters
Fix: Keep sendmail_path to an absolute binary with -t -i, and do not force extra parameters.
EXEC-014Assertions compiled and executed in productionlow
zend.assertions = 1 executes assert() calls in production. Before PHP 8.0 string assertions were evaluated as code.
Directives zend.assertions, assert.active
Fix: Set zend.assertions = -1 in production.
EXEC-015Callback invoked when unserialize() meets an unknown classlow
unserialize_callback_func is called with attacker-chosen class names while unserializing untrusted data, which can trigger autoloading of unexpected files.
Directives unserialize_callback_func
Fix: Leave unserialize_callback_func empty unless the callback is strictly validated.
EXEC-016include_path contains the current directoryinfo
A '.' entry makes relative include/require resolve against the working directory, which may be attacker-influenced (e.g. upload directories).
Directives include_path
Fix: Use absolute includes (__DIR__ . '/file.php') or remove '.' from include_path.
EXEC-017Session upload progress writes request data into session fileslow
With upload progress enabled, any multipart request stores attacker-controlled data in a session file, which turns a local file inclusion into code execution even without a session.
Directives session.upload_progress.enabled, session.upload_progress.cleanup
Fix: Set session.upload_progress.enabled = Off unless upload progress bars are used; never disable session.upload_progress.cleanup.
Filesystem and paths #
FS-001open_basedir is not setmedium
Without open_basedir, a path traversal or file-inclusion bug can reach any file the PHP user can read (/etc/passwd, other sites, keys). PHP does not treat it as a hard security boundary, but it limits the impact of common bugs.
Directives open_basedir
Fix: Set open_basedir to the application directory plus its temp/session/upload directories, each with a trailing slash.
FS-002open_basedir allows the whole filesystemmedium
An open_basedir entry of '/' (or a bare drive) disables the restriction entirely.
Directives open_basedir
Fix: List only the directories the application needs.
FS-003open_basedir entries match by prefixlow
open_basedir compares prefixes: '/var/www/site' also allows '/var/www/site-backup'. A trailing separator restricts the entry to that directory.
Directives open_basedir
Fix: End every directory entry with '/' (or '\' on Windows).
FS-004open_basedir uses relative entrieslow
Relative entries such as '.' are resolved against the current working directory, which changes with chdir() and the requested script.
Directives open_basedir
Fix: Use absolute directories only.
FS-005Security-relevant path is world-writablehigh
A path PHP loads code, certificates, sessions or logs from is writable by every local user, or sits in a world-writable directory where it can be created or replaced.
Fix: Make the path owned by root (or the deploy user) and not writable by others; use a dedicated directory instead of /tmp.
FS-006Sensitive path inside a web-served directoryhigh
Logs, sessions, uploads or caches under the document root can be downloaded, and log or session files that are both web-reachable and includable enable log-poisoning attacks.
Fix: Move the path outside the document root. Pass --webroot to make this check exact.
FS-007Configured path does not existinfo
An explicitly configured path does not exist on the audited system; PHP silently falls back or fails at runtime, and whoever creates the path first controls it.
Fix: Create the path with the intended owner and permissions, or remove the directive.
FS-008Per-directory .user.ini overrides enabledinfo
With CGI/FastCGI, any directory may carry a .user.ini that changes PERDIR settings such as auto_prepend_file. An upload vulnerability then becomes persistent code execution.
Directives user_ini.filename
Fix: Set user_ini.filename = (empty) if applications do not need per-directory settings.
FS-009HTTP file uploads enabledinfo
file_uploads lets every script receive files; disable it on hosts that never accept uploads.
Directives file_uploads
Fix: Set file_uploads = Off where uploads are not needed.
FS-010Uploads stored in the shared system temp directoryinfo
Without upload_tmp_dir, uploads land in the system temp directory shared with every other process, which eases temp-file races and LFI-via-upload techniques.
Directives upload_tmp_dir, file_uploads
Fix: Point upload_tmp_dir at a dedicated directory owned by the PHP user, mode 0700.
FS-011Configuration file writable by other userscritical
Anyone who can write a PHP configuration file or its directory can enable auto_prepend_file, load extensions or disable protections.
Fix: Make configuration files and their directories owned by root and not writable by group or others.
Information disclosure #
ERR-001Errors displayed to visitorsmedium
display_errors prints warnings and stack traces into responses, disclosing paths, queries, and sometimes credentials. PHP's built-in default is On when no php.ini is loaded.
Directives display_errors, html_errors
Fix: Set display_errors = Off and log_errors = On in production.
ERR-002Start-up errors displayedlow
display_startup_errors shows errors raised during PHP's start-up sequence in the output.
Directives display_startup_errors
Fix: Set display_startup_errors = Off in production.
ERR-003Errors are not loggedlow
Without log_errors, probing and exploitation attempts that trigger warnings leave no trace.
Directives log_errors
Fix: Set log_errors = On and configure error_log.
ERR-004PHP version disclosed in HTTP headerslow
expose_php adds an X-Powered-By header with the exact PHP version, which helps attackers pick exploits.
Directives expose_php
Fix: Set expose_php = Off.
ERR-005Function arguments included in stack traceslow
With zend.exception_ignore_args = Off, exception traces carry argument values such as passwords and tokens into logs and error pages.
Directives zend.exception_ignore_args
Fix: Set zend.exception_ignore_args = On in production.
ERR-006Error reporting disabledlow
error_reporting = 0 suppresses logging of every error, hiding attacks and bugs alike.
Directives error_reporting
Fix: Use error_reporting = E_ALL and control visibility with display_errors.
ERR-007Script path added to outgoing mail headerslow
mail.add_x_header adds X-PHP-Originating-Script with the script's UID and file name to every message.
Directives mail.add_x_header
Fix: Set mail.add_x_header = Off.
ERR-008Environment variables copied into $_ENVlow
An 'E' in variables_order copies the process environment, often holding secrets, into $_ENV where debug dumps and phpinfo() reveal it.
Directives variables_order
Fix: Use variables_order = "GPCS" and read configuration with getenv().
ERR-009Error log created world-writablelow
error_log_mode controls the permissions of a newly created error log; a world-writable log can be forged or used for log poisoning.
Directives error_log_mode
Fix: Use error_log_mode = 0640 or stricter.
ERR-010phpinfo() callableinfo
A forgotten phpinfo() page reveals configuration, paths, environment variables and cookies.
Directives disable_functions
Fix: Add phpinfo to disable_functions in production.
ERR-011Long string arguments kept in stack tracesinfo
Raising zend.exception_string_param_max_len stores more of each string argument in traces.
Directives zend.exception_string_param_max_len
Fix: Keep the default (15) or lower.
Session security #
SESS-001Uninitialised session IDs acceptedmedium
Without strict mode PHP adopts any session ID a client presents, enabling session fixation.
Directives session.use_strict_mode
Fix: Set session.use_strict_mode = 1.
SESS-002Session IDs accepted outside cookieshigh
session.use_only_cookies = 0 accepts session IDs from the URL, enabling fixation via links and leaking IDs through Referer headers and logs.
Directives session.use_only_cookies
Fix: Set session.use_only_cookies = 1.
SESS-003Transparent session IDs in URLshigh
session.use_trans_sid rewrites links to carry the session ID, which leaks through Referer, browser history, proxies and shared links.
Directives session.use_trans_sid
Fix: Set session.use_trans_sid = 0.
SESS-004Session cookies disabledmedium
session.use_cookies = 0 forces session IDs into URLs or breaks sessions entirely.
Directives session.use_cookies
Fix: Set session.use_cookies = 1.
SESS-005Session cookie readable from JavaScriptmedium
Without HttpOnly, any XSS can read document.cookie and steal the session.
Directives session.cookie_httponly
Fix: Set session.cookie_httponly = 1.
SESS-006Session cookie sent over plain HTTPmedium
Without the Secure flag the session cookie is sent over unencrypted connections and can be sniffed or injected.
Directives session.cookie_secure
Fix: Set session.cookie_secure = 1 on sites served over HTTPS.
SESS-007Session cookie without SameSite protectionlow
Without SameSite=Lax or Strict the session cookie accompanies cross-site requests, which enables CSRF.
Directives session.cookie_samesite, session.cookie_secure
Fix: Set session.cookie_samesite = "Lax" (or "Strict").
SESS-008Weak session ID entropyhigh
Session IDs need at least 128 bits of entropy (sid_length x sid_bits_per_character) to resist brute force.
Directives session.sid_length, session.sid_bits_per_character
Fix: Keep sid_length >= 32 with sid_bits_per_character = 4, or use 5/6 bits per character.
SESS-009Session files stored in a shared or listable directorymedium
Session files are named after the session ID. In a directory other users can list (such as /tmp), they can harvest IDs and hijack sessions, or plant crafted session files.
Directives session.save_path, session.save_handler
Fix: Use a dedicated session directory such as /var/lib/php/sessions with mode 1733 or 0700.
SESS-010Session files created with permissive modemedium
session.save_path = "N;MODE;/path" sets the file mode of session files; group or world access exposes session contents.
Directives session.save_path
Fix: Use mode 600 (the default).
SESS-011Long-lived sessionslow
Session data is kept for gc_maxlifetime seconds of inactivity; long lifetimes widen the window for stolen session IDs.
Directives session.gc_maxlifetime
Fix: Keep session.gc_maxlifetime at a few hours or less and implement absolute timeouts in the application.
SESS-012Default session cookie nameinfo
PHPSESSID identifies the backend as PHP.
Directives session.name
Fix: Choose an application-specific session.name.
SESS-013Persistent session cookieinfo
A non-zero cookie_lifetime stores the session cookie on disk in the browser.
Directives session.cookie_lifetime
Fix: Use session.cookie_lifetime = 0 and handle "remember me" separately.
SESS-014Session cookie shared with other hostsinfo
A cookie_domain makes the session cookie visible to every subdomain, so one compromised subdomain can read or overwrite it.
Directives session.cookie_domain
Fix: Leave session.cookie_domain empty unless sessions must span subdomains.
Resource limits and DoS #
RES-001Unlimited or very large memory_limitmedium
memory_limit = -1 lets one request exhaust server memory.
Directives memory_limit
Fix: Set memory_limit to what the application needs (typically 128M-512M).
RES-002Unlimited or long max_execution_timemedium
max_execution_time = 0 lets slow or stuck requests occupy workers forever.
Directives max_execution_time
Fix: Use 30-60 seconds for web requests (and request_terminate_timeout in FPM).
RES-003Unlimited or very large POST bodiesmedium
post_max_size = 0 removes the request body limit.
Directives post_max_size
Fix: Set post_max_size slightly above the largest legitimate upload.
RES-004Very large uploads acceptedlow
Large upload limits let clients fill the temp directory and disk.
Directives upload_max_filesize, post_max_size
Fix: Keep upload_max_filesize to the real requirement and below post_max_size.
RES-005max_input_vars raised or disabledlow
max_input_vars caps request variables and protects against hash-collision DoS (CVE-2011-4885).
Directives max_input_vars
Fix: Keep max_input_vars at 1000-5000.
RES-006Deep input nesting allowedlow
Deeply nested request arrays cost CPU and memory to parse.
Directives max_input_nesting_level
Fix: Keep max_input_nesting_level at 64.
RES-007Many files per request acceptedlow
Each uploaded file costs a temp file and file descriptor.
Directives max_file_uploads
Fix: Keep max_file_uploads at 20 or the application's real need.
RES-008Regular expression limits raisedlow
Higher PCRE limits make catastrophic backtracking (ReDoS) and stack exhaustion crashes easier.
Directives pcre.backtrack_limit, pcre.recursion_limit
Fix: Keep pcre.backtrack_limit = 1000000 and pcre.recursion_limit = 100000.
RES-009unserialize() nesting depth unlimitedlow
unserialize_max_depth = 0 lets deeply nested payloads exhaust the stack.
Directives unserialize_max_depth
Fix: Keep unserialize_max_depth = 4096 or lower.
RES-010Socket reads may block indefinitelylow
A negative or very long default_socket_timeout lets slow remote peers hold workers.
Directives default_socket_timeout
Fix: Use 60 seconds or less.
RES-011Unlimited multipart body partslow
max_multipart_body_parts bounds multipart parsing (CVE-2023-0662); when it is -1 the bound is max_input_vars + max_file_uploads, so raising those raises it too.
Directives max_multipart_body_parts, max_input_vars, max_file_uploads
Fix: Keep max_input_vars and max_file_uploads modest, or set max_multipart_body_parts.
CGI / FastCGI #
CGI-001php-cgi callable without web-server redirecthigh
cgi.force_redirect = 0 lets php-cgi be invoked directly, the precondition for argument injection such as CVE-2012-1823 and CVE-2024-4577.
Directives cgi.force_redirect
Fix: Keep cgi.force_redirect = 1 (only IIS needs it off), or move to PHP-FPM.
CGI-002PATH_INFO fix-up executes files by path prefixmedium
With cgi.fix_pathinfo = 1 a request for /uploads/avatar.jpg/x.php can make PHP execute avatar.jpg when the web server forwards any *.php path. PHP-FPM's security.limit_extensions blocks it.
Directives cgi.fix_pathinfo
Fix: Set cgi.fix_pathinfo = 0, or make sure the web server checks that the script exists (try_files $fastcgi_script_name =404) and security.limit_extensions = .php.
Debug and profiling extensions #
EXT-001Xdebug accepts debugger connections for any clientcritical
With discover_client_host (Xdebug 3) or remote_connect_back (Xdebug 2), Xdebug connects back to whoever sent the request and hands them a debugger that can evaluate arbitrary PHP.
Directives xdebug.mode, xdebug.discover_client_host, xdebug.remote_enable, xdebug.remote_connect_back
Fix: Never enable client discovery on reachable hosts; remove Xdebug from production.
EXT-002Xdebug loadedhigh
Xdebug in production slows every request and, depending on xdebug.mode, exposes debugging, tracing and profiling output.
Directives zend_extension, xdebug.mode
Fix: Do not install Xdebug on production systems.
EXT-003Development or profiling extension loadedlow
Profilers, coverage drivers and runtime-patching extensions (uopz, runkit) are not meant for production and can change behaviour or leak data.
Directives extension, zend_extension
Fix: Remove development extensions from production images.
OPcache #
OPC-001OPcache file cache enabledmedium
Compiled scripts in opcache.file_cache are executed without re-reading the source. Anyone who can write there (or an arbitrary-file-write bug) can plant opcodes and get code execution.
Directives opcache.file_cache
Fix: Disable the file cache, or keep it in a root-owned directory the PHP user cannot write except through OPcache.
OPC-002OPcache API not restrictedlow
Any script can call opcache_get_status() (revealing every cached path) or opcache_reset(). This matters on shared hosting.
Directives opcache.restrict_api
Fix: Set opcache.restrict_api to the path prefix of trusted admin scripts.
OPC-003OPcache does not isolate usersinfo
On shared hosting without validate_permission/validate_root, one user's scripts may hit another user's cached files.
Directives opcache.validate_permission, opcache.validate_root
Fix: Enable opcache.validate_permission (and validate_root with chroot) on multi-tenant hosts.
Database and credentials #
DB-001MySQL LOAD DATA LOCAL enabledmedium
A malicious or spoofed MySQL server can ask the client to send any local file the PHP user can read.
Directives mysqli.allow_local_infile
Fix: Set mysqli.allow_local_infile = Off, or restrict mysqli.local_infile_directory.
DB-002Credentials stored in PHP configurationmedium
Default passwords in INI files are readable by every user that can read the configuration and are printed by phpinfo() and ini_get_all().
Directives mysqli.default_pw, mysql.default_password, odbc.default_pw, ibase.default_password, pdo_odbc.default_pw
Fix: Pass credentials from the application's secret storage instead.
DB-003SQLite safety features relaxedlow
sqlite3.defensive = Off allows SQL to corrupt the database file; sqlite3.extension_dir enables SQLite3::loadExtension(), which loads native code.
Directives sqlite3.defensive, sqlite3.extension_dir
Fix: Keep sqlite3.defensive = On and leave sqlite3.extension_dir unset.
Character encoding #
ENC-001Unsafe default character setmedium
Multi-byte charsets such as GBK, Big5 or Shift_JIS let a trailing byte swallow escape characters (addslashes/escaping bypass, SQL injection); an empty charset leaves browsers guessing (XSS).
Directives default_charset
Fix: Set default_charset = "UTF-8".
ENC-002mbstring function overloading enabledmedium
mbstring.func_overload silently changes strlen()/substr() into multibyte versions, breaking binary-safe code such as cryptography and length checks. Removed in PHP 8.0.
Directives mbstring.func_overload
Fix: Set mbstring.func_overload = 0 and call mb_* functions explicitly.
ENC-003Multibyte script parsing enabledlow
zend.multibyte lets scripts be parsed in non-ASCII-compatible encodings such as Shift_JIS, which complicates reviewing code and can hide payloads.
Directives zend.multibyte
Fix: Set zend.multibyte = Off unless legacy encodings are required.
ENC-004Automatic input encoding translationlow
mbstring.encoding_translation converts request input before the application validates it, which can undo validation done on raw bytes.
Directives mbstring.encoding_translation
Fix: Set mbstring.encoding_translation = Off and convert explicitly.
Configuration hygiene #
CFG-001Syntax problem in configuration filelow
Lines PHP cannot parse are ignored or stop INI parsing at that point, so later settings silently do not apply.
Fix: Fix the reported lines; use ';' for comments.
CFG-002Obsolete directiveinfo
Directives removed from PHP are ignored. Settings such as safe_mode or magic_quotes_gpc give a false sense of protection; register_globals = On is critical on the old versions that still honour it.
Fix: Remove obsolete directives and use their modern replacements.
CFG-003Unknown directive resembling a known onelow
PHP ignores unknown directive names (and names are case-sensitive), so a typo such as 'display_error' leaves the intended protection unset.
Fix: Correct the directive name.
CFG-004Directive redefined with a different valueinfo
When php.ini, scan-dir files and pool settings disagree, the last one read wins. Reviewers looking at only one file get the wrong picture.
Fix: Keep each security directive in one place.
CFG-005Per-directory override that PHP ignoreslow
.user.ini and .htaccess can only change PHP_INI_PERDIR/PHP_INI_ALL directives. Hardening attempted there for PHP_INI_SYSTEM directives (disable_functions, allow_url_fopen, expose_php, ...) does not take effect.
Fix: Move the setting to php.ini or to php_admin_value in the FPM pool / Apache vhost.
CFG-006No php.ini loaded: built-in defaults in effectmedium
Without php.ini, PHP runs with compiled-in defaults: display_errors = On, register_argc_argv = On, expose_php = On, enable_dl = On and no disable_functions. Official Docker images ship this way.
Fix: Copy php.ini-production to php.ini and adjust it.
CFG-007Value depends on an environment variableinfo
${VAR} is expanded by PHP at start-up from its own environment, so a static audit cannot know the effective value; rules evaluated the literal text.
Fix: Check the variable in the PHP process environment, or use a literal value.
CFG-008Development configuration used in productionlow
The combination of display_errors, zend.assertions and mysqlnd memory statistics matches php.ini-development.
Directives display_errors, zend.assertions, mysqlnd.collect_memory_statistics
Fix: Start from php.ini-production.
CFG-009Conditional [PATH=]/[HOST=] sectioninfo
Directives in [PATH=...] or [HOST=...] sections apply only to matching requests under CGI/FastCGI; they are audited as separate overlays.
Fix: Verify these sections still match deployed paths and hosts.
CFG-010Deprecated directiveinfo
Deprecated directives set to a non-default value still work but emit warnings and will disappear in a future release.
Fix: Plan to remove the directive; remove it now from .user.ini/.htaccess on PHP versions affected by CVE-2026-109619.
PHP-FPM pools #
FPM-001FastCGI port reachable from the networkcritical
FastCGI has no authentication. Anyone who reaches the port can pass PHP_VALUE / PHP_ADMIN_VALUE (e.g. auto_prepend_file = php://input) and execute code.
Fix: Listen on a Unix socket or 127.0.0.1, and set listen.allowed_clients; never publish the port outside the host or container network.
FPM-002Non-PHP files executable by the poolhigh
security.limit_extensions restricts which files FPM will execute. An empty list or image/text extensions turn uploaded files into code.
Fix: Use security.limit_extensions = .php
FPM-003FastCGI socket writable by every usermedium
A world-writable FPM socket lets any local user send FastCGI requests and run code as the pool user.
Fix: Use listen.mode = 0660 with listen.owner/listen.group set to the web server.
FPM-004Pool workers run as roothigh
Running PHP as root turns any application bug into full system compromise.
Fix: Run each pool as a dedicated unprivileged user and group.
FPM-005Status or ping endpoint enabledlow
pm.status_path and ping.path expose pool internals (client IPs, request URIs) if the web server forwards them.
Fix: Remove them or restrict access in the web server.
FPM-006Full environment passed to PHPlow
clear_env = no gives PHP every environment variable of the FPM master.
Fix: Keep clear_env = yes and pass only needed variables with env[NAME].
FPM-007Secret stored in pool configurationmedium
Literal secrets in env[] entries end up in configuration backups and in phpinfo()/$_SERVER.
Fix: Reference the master environment (env[DB_PASSWORD] = $DB_PASSWORD) or use a secret store.
FPM-008Workers are dumpablelow
process.dumpable = yes allows core dumps and ptrace of workers by the same user, exposing secrets held in memory.
Fix: Keep process.dumpable = no.
Apache .htaccess #
HTA-001Non-PHP files mapped to the PHP handlerhigh
AddType/AddHandler/SetHandler mapping images, text or every file to PHP makes uploads executable.
Fix: Map only .php to the PHP handler, inside <FilesMatch "\.php$">.
PHP version support #
VULN-001PHP branch without security supporthigh
Branches past their end of life receive no security fixes, so every vulnerability found after that date stays open. A branch nearing its end of life is reported early.
Fix: Upgrade to a supported PHP branch (see php.net/supported-versions.php).
VULN-002Known vulnerabilities depend on the exact PHP versioninfo
Some known CVEs apply to this configuration, but the exact PHP patch version could not be read from the system (php_version.h, dpkg, apk or Homebrew), so the scanner cannot tell whether the fix is installed.
Fix: Pass --php-version X.Y.Z (from `php -v` run by you), or scan with --root so package metadata can be read.
VULN-003Publicly disclosed CVEs affect this PHP versionhigh
PHP releases fix publicly disclosed vulnerabilities that do not depend on a particular setting (parsers, extensions, bundled libraries). The finding lists every CVE fixed in a later release of this branch and takes the severity of the worst one; end-of-life branches are covered by VULN-001. CVEs whose exposure depends on the configuration are reported under their own IDs instead.
Fix: Upgrade to the latest release of a supported PHP branch.
Known vulnerabilities #
CVE-2018-10545FPM workers can bypass OPcache access controlsmedium
Dumpable FPM child processes let one pool read another pool's OPcache data via ptrace. Fixed in PHP 7.0.29, 7.1.16, 7.2.4.
Fix: Upgrade; keep process.dumpable = no.
CVE-2018-19518imap_open() runs shell commandshigh
Before the fix, rsh/ssh mailbox names in imap_open() could inject commands; there was no imap.enable_insecure_rsh switch. Fixed in PHP 7.0.33, 7.1.25, 7.2.13.
Fix: Upgrade and keep imap.enable_insecure_rsh = Off.
CVE-2019-11043PHP-FPM env_path_info underflow (remote code execution)critical
With nginx configurations that use fastcgi_split_path_info with a regex that can be broken by a newline, a crafted URL corrupts FPM memory and leads to remote code execution (exploited in the wild). Fixed in PHP 7.1.33, 7.2.24, 7.3.11.
Fix: Upgrade; add try_files $fastcgi_script_name =404 before fastcgi_pass.
CVE-2019-11048Upload temp files left behind by long namesmedium
Long file or variable names in multipart requests exhaust memory and leave temporary upload files on disk. Fixed in PHP 7.2.31, 7.3.18, 7.4.6.
Fix: Upgrade.
CVE-2020-7062Crash in session upload progressmedium
A crafted upload with session upload progress enabled dereferences a NULL pointer and crashes the worker. Fixed in PHP 7.2.28, 7.3.15, 7.4.3.
Fix: Upgrade, or set session.upload_progress.enabled = Off.
CVE-2020-7070Encoded cookie names allow __Host- spoofingmedium
PHP URL-decodes cookie names, so a crafted name is read as a __Host- cookie. Fixed in PHP 7.2.34, 7.3.23, 7.4.11.
Fix: Upgrade.
CVE-2021-21703PHP-FPM local privilege escalation to roothigh
A compromised FPM worker can write to shared memory of the root master process and escalate to root. Fixed in PHP 7.3.32, 7.4.25, 8.0.12.
Fix: Upgrade.
CVE-2022-31629__Host- cookie names can be spoofedmedium
HTTP variable name mangling lets an attacker set cookies that PHP treats as __Host- prefixed. Fixed in PHP 7.4.32, 8.0.24, 8.1.11.
Fix: Upgrade.
CVE-2023-0662Denial of service through multipart request bodiesmedium
Requests with many multipart parts consume excessive CPU; the fix introduced max_multipart_body_parts. Fixed in PHP 8.0.28, 8.1.16, 8.2.3.
Fix: Upgrade and keep max_input_vars/max_file_uploads modest.
CVE-2024-11234CRLF injection through stream proxy configurationmedium
PHP's http:// stream wrapper with a proxy configured allows CRLF injection in the request URI. Fixed in PHP 8.1.31, 8.2.26, 8.3.14.
Fix: Upgrade, or set allow_url_fopen = Off.
CVE-2024-1874Command injection through proc_open() on Windowshigh
Array-form proc_open() commands are not escaped correctly for .bat/.cmd files on Windows. Fixed in PHP 8.1.28, 8.2.18, 8.3.6.
Fix: Upgrade, or add proc_open to disable_functions if unused.
CVE-2024-2756__Host-/__Secure- cookie prefix bypassmedium
Cookie name mangling lets a non-secure origin set cookies that PHP reads as __Host-/__Secure- cookies (incomplete fix of CVE-2022-31629). Fixed in PHP 8.1.28, 8.2.18, 8.3.6.
Fix: Upgrade.
CVE-2024-4577php-cgi argument injection on Windowscritical
Windows 'Best-Fit' character conversion lets a soft hyphen in the query string become a php-cgi command-line option, giving remote code execution (exploited in the wild, e.g. default XAMPP). Fixed in PHP 8.1.29, 8.2.20, 8.3.8.
Fix: Upgrade; until then do not expose php-cgi (use PHP-FPM or mod_php).
CVE-2024-5585Bypass of the CVE-2024-1874 fixhigh
Trailing spaces in the command name bypass the CVE-2024-1874 escaping fix for proc_open() on Windows. Fixed in PHP 8.1.29, 8.2.20, 8.3.8.
Fix: Upgrade, or add proc_open to disable_functions if unused.
CVE-2024-8925Erroneous parsing of multipart form datamedium
Malformed multipart boundaries are parsed inconsistently with upstream proxies and WAFs, letting attackers smuggle form fields past filtering. Fixed in PHP 8.1.30, 8.2.24, 8.3.12.
Fix: Upgrade.
CVE-2024-8926Bypass of the CVE-2024-4577 fixcritical
Certain Windows code pages still allow php-cgi argument injection after the CVE-2024-4577 fix. Fixed in PHP 8.1.30, 8.2.24, 8.3.12.
Fix: Upgrade; do not expose php-cgi on Windows.
CVE-2024-8927cgi.force_redirect bypasshigh
An environment variable collision lets requests bypass the cgi.force_redirect protection and invoke php-cgi directly. Fixed in PHP 8.1.30, 8.2.24, 8.3.12.
Fix: Upgrade; do not expose php-cgi directly.
CVE-2024-9026PHP-FPM worker output can alter log entrieslow
With catch_workers_output, a worker can emit messages that strip characters from log lines, hiding or forging log entries. Fixed in PHP 8.1.30, 8.2.24, 8.3.12.
Fix: Upgrade, or disable catch_workers_output.
CVE-2025-1217HTTP wrapper mishandles folded headerslow
PHP's http:// stream wrapper does not handle folded headers, so response headers can be misinterpreted. Fixed in PHP 8.1.32, 8.2.28, 8.3.19, 8.4.5.
Fix: Upgrade, or set allow_url_fopen = Off.
CVE-2025-1219libxml uses the wrong content type after redirectslow
Remote documents loaded by DOM/SimpleXML through redirects are parsed with the wrong charset. Fixed in PHP 8.1.32, 8.2.28, 8.3.19, 8.4.5.
Fix: Upgrade, or set allow_url_fopen = Off.
CVE-2025-1734HTTP wrapper accepts headers without a colonlow
PHP's http:// stream wrapper accepts malformed response headers, enabling response confusion. Fixed in PHP 8.1.32, 8.2.28, 8.3.19, 8.4.5.
Fix: Upgrade, or set allow_url_fopen = Off.
CVE-2025-1736HTTP wrapper header check may omit headersmedium
PHP's http:// stream wrapper may miss user-supplied Authorization headers and send unintended headers. Fixed in PHP 8.1.32, 8.2.28, 8.3.19, 8.4.5.
Fix: Upgrade, or set allow_url_fopen = Off.
CVE-2025-1861HTTP wrapper truncates redirect locationsmedium
PHP's http:// stream wrapper truncates Location headers to 1024 bytes, so redirects can lead somewhere else. Fixed in PHP 8.1.32, 8.2.28, 8.3.19, 8.4.5.
Fix: Upgrade, or set allow_url_fopen = Off.
CVE-2026-109618Remote code execution after an out-of-memory errorcritical
When an allocation fails, PHP aborts the request and leaves request memory in an invalid state that shutdown code still uses, so a crafted request can corrupt memory and run code (exploited in the wild). Configuration only reduces exposure. Fixed in PHP 8.2.35, 8.3.36, 8.4.27, 8.5.12.
Fix: Upgrade. Until then set memory_limit = -1 with php_admin_value so applications cannot lower it, keep post_max_size at 8M (32M with uploads), and bound memory with a container or cgroup limit rather than RLIMIT_AS/RLIMIT_DATA.
CVE-2026-109619Remote code execution through stale request statecritical
Request-owned state survives a fatal error into the next request on the same worker and is used before initialisation. Confirmed paths are session upload progress and, on PHP 8.5, fatal error backtraces; other variants remain. Fixed in PHP 8.2.35, 8.3.36, 8.4.27, 8.5.12.
Fix: Upgrade. Until then set session.upload_progress.enabled = 0 in php.ini or the FPM pool (not .user.ini or ini_set()), on PHP 8.5 set fatal_error_backtraces = 0, restart every worker, and remove deprecated settings from .user.ini/.htaccess.
CVE-2026-6735XSS in the PHP-FPM status pagemedium
The FPM status endpoint reflects request data without escaping in its HTML output. Fixed in PHP 8.2.31, 8.3.31, 8.4.21, 8.5.6.
Fix: Upgrade, or remove pm.status_path / restrict it to administrators.
CVE-2026-91766HTTP wrapper leaks credentials across origins on redirecthigh
PHP's http:// stream wrapper forwards credentials to a different origin when following redirects. Fixed in PHP 8.2.34, 8.3.35, 8.4.26, 8.5.11.
Fix: Upgrade, or set allow_url_fopen = Off.
CVE-2026-91768IPv6 bypass of listen.allowed_clientshigh
listen.allowed_clients compares IPv6 addresses partially, so clients outside the list can reach the unauthenticated FastCGI port. Fixed in PHP 8.2.34, 8.3.35, 8.4.26, 8.5.11.
Fix: Upgrade; also firewall the FastCGI port or use a Unix socket.
CVE-2026-93682HTTP wrapper out-of-bounds read on empty redirectmedium
A redirect with an empty Location header makes PHP's http:// stream wrapper read out of bounds. Fixed in PHP 8.2.34, 8.3.35, 8.4.26, 8.5.11.
Fix: Upgrade, or set allow_url_fopen = Off.
No rule matches the filters.