Skip to main content

PHP

Vulkro reads PHP source with a set of dedicated detectors and a short-range taint pass, and checks composer.lock against the local CVE bundle. It does not build an endpoint map or an access model for PHP, so the API-level checks that need one do not run.

PHP is covered by vulkro (Core). Salesforce code is covered by the separate vulkro-sf binary.

vulkro scan .

What is analysed​

AreaCoverage
Project detectioncomposer.json, a Laravel artisan file, wp-config.php, or any PHP source file
Files read.php, .phtml, .php4, .php5, .phps (.inc is not read as PHP)
Request sourcesThe superglobals ($_GET, $_POST, $_REQUEST, $_COOKIE, $_FILES, $_SERVER, $_ENV, $GLOBALS) and framework request objects: Laravel, Symfony, PSR-7 / Slim / Mezzio, CodeIgniter 4, CakePHP
TaintWithin one function, through local variables (copy, . and .=, string interpolation, a ternary, and plain string helpers such as trim or sprintf). Any other call is treated as a barrier. One call into a project function is also followed (see Limits)
Taint sinksSQL queries, OS commands, HTML output (echo / print), include / require, eval / assert, unserialize, outbound fetch and file URLs
Endpoints and authNot analysed: no route map, no auth tier per endpoint
Dependenciescomposer.lock (packages and packages-dev), matched as Packagist against the local CVE bundle. See Dependencies and CVEs

Detectors​

The injection rules fire when a request value appears in the dangerous call itself, and stay silent when the matching escaper or safe form is used (prepared statements, htmlspecialchars, escapeshellarg, allowed_classes => false and so on). The rest match a risky call shape.

RuleWhat it findsCWE
PHP-SQLI-001Request input in a SQL query string89
PHP-XSS-001Request input echoed or printed without encoding79
PHP-CMDI-001Request input in system, exec, shell_exec or backticks78
PHP-CODE-001eval, assert or a variable function on request input95
PHP-LFI-001Request input in an include / require path98
PHP-EXTRACT-001extract, one-argument parse_str and similar on request input621
PHP-DESER-001unserialize of request input502
PHP-PHAR-001A phar:// path reaching a filesystem call502
PHP-SSRF-001Request input in a fetch or file URL918
PHP-UPLOAD-001An upload stored under the client's file name434
PHP-HEADER-001Request input in header(): open redirect or header injection601, 113
PHP-MAILPARAM-001Request input in the extra-parameters argument of mail()88
PHP-LDAPX-001Request input in an LDAP filter or an XPath query90, 643
PHP-SSTI-001Request input compiled as a template1336
PHP-XXE-001XML parsed with external entities enabled611
PHP-MASS-ASSIGN-001A whole request passed to an Eloquent write915
PHP-TYPEJUGGLE-001A loose == comparison on a password, hash or token697
PHP-CRYPTO-001md5 / sha1 on a secret, weak ciphers327
PHP-RAND-001rand / mt_rand used to make a token or key330
PHP-TLS-001Certificate verification turned off in an HTTPS client295
PHP-COOKIE-001Cookies or the session cookie without HttpOnly / Secure1004, 614

The taint pass reports under php-taint-sql, php-taint-command, php-taint-xss, php-taint-file-inclusion, php-taint-code, php-taint-unserialize and php-taint-ssrf. Secrets, IaC and container checks run on a PHP repository as on any other.

Example​

function find_user($conn) {
$q = "SELECT * FROM users WHERE id = " . $_GET['id'];
mysqli_query($conn, $q);
}

vulkro scan . reports this as php-taint-sql (CWE-89, High) on the mysqli_query line, with a two-step trace: the line where $_GET entered $q, then the sink. A finding with a trace is reported as proven.

Limits​

  • Short range. Taint is followed inside one function, plus one call: a request value passed to a project function whose parameter reaches a sink, or a project function that returns request data. A chain of two or more helper calls is not followed, and neither is data stored and read back later (second-order).
  • Method calls are a guess. A call through $obj->method() is matched by method name only, so such a finding has no trace and is reported at Medium confidence. A free function with one definition, or Class::method on a unique class, carries a trace.
  • No endpoint map and no auth model. Routes, middleware and auth checks are not read, so the OWASP API Top 10 checks that need an endpoint (missing auth, IDOR, function-level authorization) do not run for PHP.
  • No template escaping context. Blade {!! !!} and Twig |raw are not modelled.
  • Dynamic code is out of reach. Variable variables ($$name), dynamic dispatch and runtime include paths are not resolved.
  • Lockfile only. A project with composer.json but no composer.lock gets no dependency CVE check.

See Supported languages for how PHP compares with the other languages.