| name | sc-lang-php |
| description | PHP-specific security deep scan |
| license | MIT |
| metadata | {"author":"ersinkoc","category":"security","version":"1.0.0"} |
SC: PHP Security Deep Scan
Purpose
Detects PHP-specific security anti-patterns including deserialization gadgets, type juggling, include-based attacks, and framework-specific vulnerabilities in Laravel and WordPress. Focuses on PHP's unique type system, legacy functions, and common misconfigurations.
Activation
Activates when PHP is detected in security-report/architecture.md.
Checklist Reference
References references/php-security-checklist.md.
PHP-Specific Vulnerability Patterns
Category 1: unserialize() POP Chains
$data = unserialize($_POST['data']);
$data = json_decode($_POST['data'], true);
$data = unserialize($input, ['allowed_classes' => false]);
Category 2: phar:// Deserialization
file_exists("phar://" . $_GET['file']);
Category 3: include/require LFI/RFI
include($_GET['page'] . '.php');
$allowed = ['home', 'about', 'contact'];
$page = in_array($_GET['page'], $allowed) ? $_GET['page'] : 'home';
include($page . '.php');
Category 4: extract() Variable Overwrite
extract($_POST);
$name = $_POST['name'];
Category 5: Type Juggling (== vs ===)
if ($_POST['password'] == $storedHash) { }
if (strcmp($_POST['token'], $expectedToken) == 0) { }
if ($_POST['password'] === $storedHash) { }
if (hash_equals($expectedToken, $_POST['token'])) { }
Category 6: preg_replace /e Modifier (Legacy)
preg_replace('/.*/e', $_GET['code'], '');
preg_replace_callback('/pattern/', function($matches) { }, $input);
Category 7: Laravel Mass Assignment
class User extends Model {}
User::create($request->all());
class User extends Model {
protected $fillable = ['name', 'email'];
}
Category 8: Eloquent Raw Queries
DB::select("SELECT * FROM users WHERE name = '$name'");
User::whereRaw("name = '$name'")->get();
DB::select("SELECT * FROM users WHERE name = ?", [$name]);
User::whereRaw("name = ?", [$name])->get();
Category 9: Blade Escape Bypass
{{ $userInput }}
{!! $userInput !!}
Category 10: WordPress Security
function handle_ajax() {
$data = $_POST['data'];
}
function handle_ajax() {
check_ajax_referer('my_nonce', 'security');
$data = sanitize_text_field($_POST['data']);
}
$wpdb->query("SELECT * FROM users WHERE id = " . $_GET['id']);
$wpdb->prepare("SELECT * FROM users WHERE id = %d", $_GET['id']);
Category 11: PDO Prepared Statements
$pdo->query("SELECT * FROM users WHERE id = " . $_GET['id']);
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
Category 12: file_get_contents SSRF
$content = file_get_contents($_GET['url']);
$url = filter_var($_GET['url'], FILTER_VALIDATE_URL);
$parsed = parse_url($url);
if (!in_array($parsed['host'], $allowedHosts)) die('Blocked');
Category 13: Session Security
session_start();
session_start();
session_regenerate_id(true);
ini_set('session.use_only_cookies', 1);
ini_set('session.use_strict_mode', 1);
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');
Category 14: assert() Code Execution
assert($_GET['expr']);
Category 15: Composer Supply Chain
- Check for typosquatted package names in
composer.json
- Review
scripts section for dangerous post-install hooks
- Verify
composer.lock is committed and reviewed
Category 16: curl_exec Misuse
$ch = curl_init($_GET['url']);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$result = curl_exec($ch);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
Category 17: md5/sha1 for Security
$hash = md5($password);
$hash = md5($password . $salt);
$hash = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($input, $hash)) { }
Category 18: strcmp() Bypass
if (strcmp($_POST['token'], $secret) == 0) { }
if (!is_string($_POST['token'])) die('Invalid');
if (hash_equals($secret, $_POST['token'])) { }
Category 19: PHP 8.x Security Features
- Fibers: no direct security risk but async code may introduce race conditions
- JIT: limited attack surface but potential for new bug classes
- Named arguments: check for parameter name injection in dynamic calls
- Enums: use for type-safe comparisons (replaces loose string matching)
Category 20: Error Disclosure
ini_set('display_errors', 1);
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php/error.log');
Output Format
Finding: PHP-{NNN}
- Title: PHP-specific vulnerability
- Severity: Critical | High | Medium | Low
- Confidence: 0-100
- File: file/path:line
- Vulnerability Type: CWE-XXX
- Description: What was found
- Remediation: PHP-idiomatic fix
- References: CWE link, PHP documentation