Eresus php audit
Production-ready AI AppSec skills for SAST, threat modeling, remediation, PR security review, and serialization abuse analysis.
npx -y skills add EresusSecurity/appsec-skills --skill eresus-php-auditAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Deep PHP-specific security audit skill covering injection, deserialization, file operations, auth bypass, POP chain discovery, and CMS-specific patterns. Trigger when auditing PHP code: "audit this PHP app", "find PHP security issues", "check Laravel/WordPress for vulnerabilities", "PHP SAST review", "check for PHP deserialization", "review this WordPress plugin". Includes scripts/rules.json for programmatic rule lookup.
SKILL.md
11.0 KB, as published. Nobody here has run it
PHP Security Audit
Purpose
Perform a comprehensive, depth-first security audit of PHP codebases. This skill provides the complete knowledge of Kunlun-M's CVI rule set, organized by vulnerability class, plus framework-specific patterns for Laravel, WordPress, Symfony, and modern PHP 8.x applications.
Use view_file and grep_search exclusively. No terminal commands.
Audit Workflow
Phase 1: Reconnaissance
- Identify the PHP framework/CMS (Laravel, WordPress, Symfony, CodeIgniter, raw PHP)
- Check
composer.json/composer.lockfor known vulnerable dependencies - Map entry points: routes, controllers, REST endpoints, admin pages, AJAX handlers
- Identify the autoloader and class loading mechanism
- Check PHP version requirements (
phpconstraint incomposer.json)
Phase 2: Entry Point Discovery
Inspired by Kunlun-M's EntranceFinder plugin — systematically find all user-facing entry points:
- Direct file access — find all
.phpfiles that can be accessed directly (not included/required) - Route definitions — check framework routing files
- AJAX handlers — WordPress
wp_ajax_*, Laravel API routes, custom handlers - CLI entry — Artisan commands, WP-CLI commands, custom scripts
- Cron jobs — scheduled tasks that process external data
Search patterns for entry points:
- Files with
$_GET,$_POST,$_REQUEST,$_FILES,$_COOKIE,$_SERVER - Files with
file_get_contents('php://input') - Laravel:
Route::get,Route::post,Route::any,Route::resource - WordPress:
add_action('wp_ajax_,add_action('rest_api_init - Symfony:
#[Route(,@Route(,routing.yamldefinitions
CVI Rules — Injection
CVI-1001: SSRF
Search for HTTP request functions with user-controlled URLs:
curl_setopt($ch, CURLOPT_URL, $userInput)
file_get_contents($userUrl)
fopen($userUrl, 'r')
$client->get($userInput) // Guzzle
$client->request('GET', $userInput)
Severity: HIGH — can lead to internal service access, cloud metadata theft
Trace: Check if URL comes from $_GET, $_POST, database with user data
CVI-1002: SQL Injection
Search for raw SQL construction:
$db->query("SELECT * FROM users WHERE id = " . $_GET['id'])
$wpdb->query("SELECT * FROM $table WHERE id = $id")
$pdo->query("SELECT ... $var ...")
mysqli_query($conn, "... $var ...")
Safe patterns: $pdo->prepare(), $wpdb->prepare(), Eloquent query builder
Severity: CRITICAL when user input reaches query without parameterization
CVI-1003: Command Injection
Search for shell execution functions:
system($userInput)
exec($userInput)
passthru($userInput)
shell_exec($userInput)
`$userInput` (backticks)
popen($userInput, 'r')
proc_open($userInput, ...)
pcntl_exec($userInput)
Severity: CRITICAL — always results in RCE if input is user-controlled
CVI-1004: Code Injection
Search for dynamic code execution:
eval($userInput)
assert($userInput) // PHP < 8.0
preg_replace('/.*/e', $replacement, $subject) // deprecated /e modifier
create_function($args, $userInput)
call_user_func($userInput, $args)
call_user_func_array($userInput, $args)
array_map($userInput, $data)
usort($data, $userInput)
Severity: CRITICAL if any argument is user-controlled
CVI-1005: XSS
Search for unescaped output:
echo $_GET['input']
echo $userInput // without htmlspecialchars()
<?= $userInput ?>
print($userInput)
printf("%s", $userInput) // in HTML context
Safe patterns: htmlspecialchars($var, ENT_QUOTES, 'UTF-8'), esc_html() (WP), {{ $var }} (Blade)
Dangerous: {!! $var !!} (Laravel Blade raw), | raw (Twig)
CVI-1006: File Inclusion (LFI/RFI)
include($userInput)
include_once($userInput)
require($userInput)
require_once($userInput)
Severity: CRITICAL if path is user-controlled
Check: Is allow_url_include enabled? (RFI)
CVI-1007: File Operations
file_get_contents($userInput) // path traversal read
file_put_contents($userInput, $data) // arbitrary file write
unlink($userInput) // arbitrary file delete
copy($src, $userInput) // arbitrary file placement
rename($old, $userInput) // arbitrary file move
readfile($userInput) // information disclosure
Severity: HIGH to CRITICAL depending on operation
CVI-1008: XML External Entity (XXE)
$doc = new DOMDocument()
$doc->loadXML($userInput) // XXE if no protection
simplexml_load_string($userInput) // XXE
$reader = new XMLReader()
$reader->xml($userInput) // XXE
Safe: libxml_disable_entity_loader(true) (deprecated PHP 8.0+, secure by default)
CVI Rules — Deserialization
CVI-2001: PHP Object Injection
unserialize($userInput)
unserialize($_COOKIE['data'])
unserialize(base64_decode($_GET['data']))
Severity: CRITICAL — Property-Oriented Programming (POP) chain exploitation Gadget hunting: Search for classes with:
__wakeup()— called on deserialization__destruct()— called on object destruction__toString()— called on string cast__call()— called on undefined method__get()/__set()— called on property access
CVI-2002: PHP Unserialize Chain Discovery
Kunlun-M's phpunserializechain plugin methodology — trace POP chains:
- Find the entry sink:
unserialize()with user input - Find gadget classes: Classes with magic methods that perform I/O
- Trace the chain:
__destruct()→ calls method → file write / command exec - Popular chains:
- Laravel:
PendingBroadcast→__destruct()→dispatch() - Symfony:
Process→__destruct()→stop()→ command execution - WordPress: Various plugin-specific chains
- Monolog:
BufferHandler→__destruct()→close()→ arbitrary write
- Laravel:
CVI Rules — Authentication & Authorization
CVI-3001: Authentication Bypass
// Weak comparison
if ($_POST['password'] == $storedPassword) // type juggling: "0" == 0
if (md5($_POST['password']) == $storedHash) // magic hash: "0e..." == 0
// Missing auth check
// Check if sensitive functions lack is_admin(), current_user_can(), auth check
Key pattern: == vs === for authentication — PHP type juggling attack
CVI-3002: Session & Cookie Security
session_set_cookie_params(['secure' => false])
setcookie($name, $value) // missing secure, httponly, samesite flags
$_SESSION['admin'] = $_POST['is_admin'] // user-controlled session data
session_id($_GET['sessid']) // session fixation
CVI-3003: CSRF
// Missing CSRF token verification
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// No token check before processing
}
// WordPress: Missing nonce verification
// check_ajax_referer() missing
// wp_verify_nonce() missing
CVI Rules — Configuration & Information Disclosure
CVI-4001: Information Disclosure
phpinfo()
error_reporting(E_ALL)
display_errors = On
var_dump($sensitiveData)
print_r($debug)
CVI-4002: Hardcoded Secrets
$password = "hardcoded"
$apiKey = "sk_live_..."
$dbPassword = "root"
define('DB_PASSWORD', 'actual_password')
CVI-4003: Dangerous PHP Configuration
allow_url_fopen = On // enables RFI via include()
allow_url_include = On // enables remote file inclusion
expose_php = On // version disclosure
register_globals = On // variable injection (legacy)
magic_quotes_gpc = Off // no auto-escaping (legacy)
open_basedir // check if properly set
disable_functions // check if dangerous funcs are disabled
Framework-Specific Deep Checks
Laravel
- Check
.envfile exposure (web-accessible.env) - Check
APP_DEBUG=truein production - Check
APP_KEYrotation - Check for
{!! !!}raw Blade output with user data - Check Eloquent mass assignment:
$fillablevs$guarded - Check Gate/Policy authorization on controllers
- Check
Route::any()over-permissive routing - Check file upload handling: stored path, extension validation
- Check queue job deserialization (jobs are serialized/unserialized)
WordPress
- Check for direct file access without
defined('ABSPATH')check - Check
$wpdb->prepare()usage (must use %s, %d placeholders) - Check
update_option()/add_option()with user input - Check
wp_remote_get()/wp_remote_post()for SSRF - Check
is_admin()(checks admin page, NOT admin privilege — usecurrent_user_can()) - Check nonce verification on all form handlers
- Check
esc_html(),esc_attr(),esc_url(),wp_kses()usage - Check REST API permission callbacks (
permission_callbackmust not be__return_truefor sensitive data) - Check
sanitize_text_field(),absint(),wp_unslash()input sanitization
Symfony
- Check
@Routewith missing security annotations - Check Twig
| rawfilter with user data - Check
kernel.debugin production - Check voter/access decision manager configuration
- Check CSRF token service usage
Supply Chain Checks
Composer Dependencies
- Check
composer.lockfor known CVEs (compare against advisories) - Check for abandoned packages
- Check for packages with
eval(),system(),exec()in install scripts - Check post-install/post-update scripts in
composer.json
Red Flags Checklist
- Any use of
unserialize()with external data - Any use of
eval(),assert(),create_function() -
==comparison for authentication/authorization -
$_GET/$_POSTdirectly in SQL queries -
$_GET/$_POSTininclude()/require() - File operations with user-controlled paths
-
echo/printof user input without encoding - Missing CSRF token verification on state-changing actions
-
APP_DEBUG=trueordisplay_errors=Onin production - Hardcoded credentials in source code
-
allow_url_includeenabled - WordPress:
is_admin()used for privilege checks (wrong function) - Laravel:
{!! $userInput !!}in Blade templates
Report Format
For each finding, report:
### CVI-[ID]: [Vulnerability Class]
**Severity**: [LOW/MEDIUM/HIGH/CRITICAL]
**Confidence**: [LOW/MEDIUM/HIGH]
**File**: [path]:[line]
**Vulnerable Code**:
[show the code]
**Data Flow**:
[source] → [intermediaries] → [sink]
**Impact**: [what an attacker achieves]
**Remediation**: [specific fix with code example]
**CVI Reference**: CVI-[xxxx]
Tooling Constraints
Use ONLY:
view_file— read source codegrep_search— find patterns across the codebase
Do NOT use any terminal commands.