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
Category Code executionScope configWeakness CWE-98

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
Category Code executionScope configWeakness CWE-918

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
Category Code executionScope configWeakness CWE-94

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
Category Code executionScope configWeakness CWE-506

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
Category Code executionScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-78

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
Category Code executionScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-693

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
Category Code executionScope configWeakness CWE-749

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
Category Code executionScope configWeakness CWE-114

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
Category Code executionScope configWeakness CWE-502

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
Category Code executionScope configWeakness CWE-345

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
Category Code executionScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-88

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
Category Code executionScope configWeakness CWE-78

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
Category Code executionScope configWeakness CWE-88

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
Category Code executionScope configProfile production onlyWeakness CWE-489

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
Category Code executionScope configWeakness CWE-502

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
Category Code executionScope configWeakness CWE-427

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
Category Code executionScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-98

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
Category Filesystem and pathsScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-22

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
Category Filesystem and pathsScope configWeakness CWE-22

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
Category Filesystem and pathsScope configWeakness CWE-22

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
Category Filesystem and pathsScope configWeakness CWE-22

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
Category Filesystem and pathsScope configWeakness CWE-732

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
Category Filesystem and pathsScope configWeakness CWE-538

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
Category Filesystem and pathsScope config

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
Category Filesystem and pathsScope configSAPIs cgi, fpm, litespeed, unknownWeakness CWE-15

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
Category Filesystem and pathsScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-434

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
Category Filesystem and pathsScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-377

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
Category Filesystem and pathsScope fileWeakness CWE-732

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
Category Information disclosureScope configSAPIs apache2, cgi, fpm, litespeed, unknownDevelopment infoWeakness CWE-209

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
Category Information disclosureScope configSAPIs apache2, cgi, fpm, litespeed, unknownDevelopment infoWeakness CWE-209

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
Category Information disclosureScope configWeakness CWE-778

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
Category Information disclosureScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-200

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
Category Information disclosureScope configProfile production onlyWeakness CWE-532

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
Category Information disclosureScope configWeakness CWE-778

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
Category Information disclosureScope configWeakness CWE-200

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
Category Information disclosureScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-526

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
Category Information disclosureScope configWeakness CWE-732

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
Category Information disclosureScope configSAPIs apache2, cgi, fpm, litespeed, unknownProfile production onlyWeakness CWE-200

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
Category Information disclosureScope configWeakness CWE-532

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-384

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-598

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-598

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-598

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-1004

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-614

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-1275

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-331

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-552

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
Category Session securityScope configWeakness CWE-276

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-613

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-200

PHPSESSID identifies the backend as PHP.

Directives session.name

Fix: Choose an application-specific session.name.

SESS-013Persistent session cookieinfo
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-539

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
Category Session securityScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-565

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
Category Resource limits and DoSScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-770

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
Category Resource limits and DoSScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-400

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
Category Resource limits and DoSScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-770

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
Category Resource limits and DoSScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-770

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
Category Resource limits and DoSScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-407

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
Category Resource limits and DoSScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-674

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
Category Resource limits and DoSScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-770

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
Category Resource limits and DoSScope configWeakness CWE-1333

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
Category Resource limits and DoSScope configWeakness CWE-674

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
Category Resource limits and DoSScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-400

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
Category Resource limits and DoSScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-770

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
Category CGI / FastCGIScope configSAPIs cgi, unknownWeakness CWE-88

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
Category CGI / FastCGIScope configSAPIs cgi, fpm, litespeed, unknownWeakness CWE-434

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
Category Debug and profiling extensionsScope configDevelopment highWeakness CWE-489

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
Category Debug and profiling extensionsScope configDevelopment infoWeakness CWE-489

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
Category Debug and profiling extensionsScope configProfile production onlyWeakness CWE-489

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
Category OPcacheScope configWeakness CWE-494

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
Category OPcacheScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-284

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
Category OPcacheScope configSAPIs cgi, fpm, litespeed, unknownWeakness CWE-653

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
Category Database and credentialsScope configWeakness CWE-73

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
Category Database and credentialsScope configWeakness CWE-260

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
Category Database and credentialsScope configWeakness CWE-114

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
Category Character encodingScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-838

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
Category Character encodingScope configWeakness CWE-704

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
Category Character encodingScope configWeakness CWE-838

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
Category Character encodingScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-838

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
Category Configuration hygieneScope file

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
Category Configuration hygieneScope file

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
Category Configuration hygieneScope file

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
Category Configuration hygieneScope config

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
Category Configuration hygieneScope config

.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
Category Configuration hygieneScope config

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
Category Configuration hygieneScope file

${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
Category Configuration hygieneScope configProfile production only

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
Category Configuration hygieneScope file

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
Category Configuration hygieneScope file

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
Category PHP-FPM poolsScope poolWeakness CWE-306

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
Category PHP-FPM poolsScope poolWeakness CWE-434

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
Category PHP-FPM poolsScope poolWeakness CWE-276

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
Category PHP-FPM poolsScope poolWeakness CWE-250

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
Category PHP-FPM poolsScope poolWeakness CWE-200

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
Category PHP-FPM poolsScope poolWeakness CWE-526

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
Category PHP-FPM poolsScope poolWeakness CWE-260

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
Category PHP-FPM poolsScope poolWeakness CWE-528

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
Category Apache .htaccessScope fileWeakness CWE-434

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
Category PHP version supportScope configWeakness CWE-1104

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
Category PHP version supportScope config

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
Category PHP version supportScope config

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
Category Known vulnerabilitiesScope configSAPIs fpm, unknownWeakness CWE-284

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
Category Known vulnerabilitiesScope configWeakness CWE-78

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
Category Known vulnerabilitiesScope configSAPIs fpm, unknownWeakness CWE-787

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
Category Known vulnerabilitiesScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-190

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
Category Known vulnerabilitiesScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-476

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
Category Known vulnerabilitiesScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-565

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
Category Known vulnerabilitiesScope configSAPIs fpm, unknownWeakness CWE-787

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
Category Known vulnerabilitiesScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-565

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
Category Known vulnerabilitiesScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-400

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
Category Known vulnerabilitiesScope configWeakness CWE-93

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
Category Known vulnerabilitiesScope configWeakness CWE-78

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
Category Known vulnerabilitiesScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-565

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
Category Known vulnerabilitiesScope configSAPIs cgi, unknownWeakness CWE-78

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
Category Known vulnerabilitiesScope configWeakness CWE-78

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
Category Known vulnerabilitiesScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-436

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
Category Known vulnerabilitiesScope configSAPIs cgi, unknownWeakness CWE-88

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
Category Known vulnerabilitiesScope configSAPIs cgi, unknownWeakness CWE-284

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
Category Known vulnerabilitiesScope poolWeakness CWE-117

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
Category Known vulnerabilitiesScope configWeakness CWE-436

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
Category Known vulnerabilitiesScope configWeakness CWE-436

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
Category Known vulnerabilitiesScope configWeakness CWE-436

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
Category Known vulnerabilitiesScope configWeakness CWE-20

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
Category Known vulnerabilitiesScope configWeakness CWE-131

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
Category Known vulnerabilitiesScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-416

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
Category Known vulnerabilitiesScope configSAPIs apache2, cgi, fpm, litespeed, unknownWeakness CWE-416

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
Category Known vulnerabilitiesScope poolWeakness CWE-79

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
Category Known vulnerabilitiesScope configWeakness CWE-200

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
Category Known vulnerabilitiesScope poolWeakness CWE-284

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
Category Known vulnerabilitiesScope configWeakness CWE-125

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.