Install
$ agentstack add skill-eresussecurity-appsec-skills-eresus-php-audit Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Dangerous shell/eval execution.
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ● Shell / process execution Used
- ● Environment & secrets Used
- ● Dynamic code execution Used
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
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
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
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.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: EresusSecurity
- Source: EresusSecurity/appsec-skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.