security-audit

Installation
SKILL.md

Security Audit Skill for Laravel/PHP Projects

You are a security audit agent. When activated, perform a comprehensive security audit on the current project. Follow each phase in order and report findings clearly.

Phase 1: Vulnerable Package Detection

Scan composer.lock for known vulnerable packages:

# Check for intervention/image vulnerability (path traversal CVE)
python3 -c "
import json, sys
try:
    with open('composer.lock') as f:
        data = json.load(f)
    vulns = []
    checks = {
        'intervention/image': lambda v: int(v.lstrip('v').split('.')[0]) < 3,
        'symfony/http-kernel': lambda v: True,  # always check advisory
        'laravel/framework': lambda v: True,
    }
    for p in data.get('packages', []):
        if p['name'] in checks:
            ver = p['version'].lstrip('v')
            vulns.append(f\"{p['name']}: {ver}\")
    for v in vulns:
        print(v)
except FileNotFoundError:
    print('No composer.lock found')
"

Also run composer audit if available.

Action items:

  • Flag intervention/image < v3 as CRITICAL (path traversal, allows reading .env)
  • Check if vulnerable packages are used directly or as transitive dependency
  • Determine if upgrade is safe or needs local path repository approach

Phase 2: Malware & Webshell Scanner

Search for malicious files across these locations:

2a. PHP files in upload/storage directories (should NOT exist)

find storage/app/public public/uploads public/images public/storage -name "*.php" -type f 2>/dev/null

2b. Suspicious file patterns

Search for files with:

  • Random 5-character names: [a-z0-9]{5}.php
  • Known malware names: stmept, guard.sh, wp-admin.php, wp-cron.php, cache.php, test.php, unzip.php, bootstrap.cache.php, themes.php, menu.php, php8.php
  • Binary executables in web directories
  • Files with double extensions: .php.jpg, .jpg.php
  • Temporary PHP files: tmp_*.php

2c. Dangerous code patterns in PHP files

Search app/ and public/ directories for:

eval(
base64_decode(
exec(
system(
passthru(
shell_exec(
gzinflate(
str_rot13(
assert(
preg_replace with /e modifier
$_GET/$_POST/$_REQUEST used with eval/exec
create_function(

2d. Crypto miner detection

# Check for known miner processes
pgrep -f "xmrig\|stmept\|minerd\|cpuminer" 2>/dev/null

# Check for miner binaries
find . -name "stmept" -o -name "xmrig" -o -name "minerd" 2>/dev/null

# Check for mining pool connections in code
grep -r "supportxmr\|nanopool\|minergate\|coinhive" . --include="*.php" --include="*.sh" --include="*.conf" 2>/dev/null

2e. Injected .htaccess files

# Check all .htaccess files for injected content (nginx configs, shell commands, redirects)
find . -name ".htaccess" -exec grep -l "sudo\|nginx\|server_name\|proxy_pass\|RewriteRule.*http" {} \;

Phase 3: Configuration Security Check

3a. Storage directory protection

Check if storage/app/public/.htaccess exists with PHP execution blocking:

<FilesMatch "\.(?:php|phtml|phar|php[0-9]|inc)$">
    Order Deny,Allow
    Deny from all
</FilesMatch>

If missing, CREATE IT - this is the #1 defense against uploaded webshells.

3b. Public .htaccess hardening

Check public/.htaccess for:

  • Block PHP execution in storage/uploads dirs: RewriteRule ^storage/.*\.php$ - [F,L]
  • Security headers: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection
  • Block sensitive file access: .env, .log, .sql, .bak

3c. File upload security

Search for these risky patterns in Filament/Controller code:

  • editableSvgs(true) - SVG can contain JavaScript (XSS) and XXE attacks
  • preserveFilenames() - Original filenames can be manipulated for path traversal
  • Missing mime type validation on upload fields
  • Missing file extension validation

3d. Credential exposure

Check .env file types present (DO NOT output actual values):

grep -E "^[A-Z_]+=." .env | sed 's/=.*/=***/' | grep -iE "key|secret|password|token|mail|sendgrid|aws|stripe|paypal"

Phase 4: Server-Level Checks (if accessible)

4a. Web server user

ps aux | grep -E "nginx|php-fpm|apache" | head -5

CRITICAL if running as root - web server must run as unprivileged user (www-data/nginx).

4b. Sudoers audit

grep -i "NOPASSWD" /etc/sudoers /etc/sudoers.d/* 2>/dev/null

Flag any NOPASSWD: ALL entries - especially for www-data, nginx, or CI users like gitlab-runner.

4c. Crontab persistence check

crontab -l 2>/dev/null
crontab -u www-data -l 2>/dev/null
ls -la /etc/cron.d/ /etc/cron.daily/ 2>/dev/null

4d. Active miner/backdoor processes

pgrep -a -f "xmrig\|stmept\|minerd\|cryptonight"
netstat -tlnp 2>/dev/null | grep -E ":3333|:4444|:5555|:8888"

Phase 5: Auto-Fix (Apply Hardening)

When confirmed by user, apply these fixes:

Fix 1: Create storage/.htaccess (SAFE - zero breaking changes)

<IfModule mod_php.c>
    php_flag engine off
</IfModule>
<IfModule mod_php7.c>
    php_flag engine off
</IfModule>
<IfModule mod_php8.c>
    php_flag engine off
</IfModule>
<FilesMatch "\.(?:php|phtml|phar|php[0-9]|inc)$">
    Order Deny,Allow
    Deny from all
</FilesMatch>

Fix 2: Harden public/.htaccess (SAFE - zero breaking changes)

Add before existing rewrite rules:

# Block PHP execution in storage/upload directories
RewriteRule ^storage/.*\.php$ - [F,L]
RewriteRule ^uploads/.*\.php$ - [F,L]
RewriteRule ^images/.*\.php$ - [F,L]

Add after </IfModule>:

# Security Headers
<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
    Header set X-Frame-Options "SAMEORIGIN"
    Header set X-XSS-Protection "1; mode=block"
</IfModule>

# Block access to sensitive files
<FilesMatch "\.(env|log|sql|bak|conf|ini)$">
    Order Deny,Allow
    Deny from all
</FilesMatch>

Fix 3: Generate nginx security config (SAFE - needs manual include)

Create nginx-security.conf:

location ~ ^/storage/.*\.php$ { deny all; return 403; }
location ~ /\.(env|git|htaccess|htpasswd) { deny all; return 404; }
location ~* \.(sql|bak|log|conf|ini)$ { deny all; return 404; }
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;

Fix 4: Vulnerable package mitigation (CHECK for breaking changes)

For packages with breaking changes (e.g., intervention/image v2 → v3):

  1. Copy package from vendor/ to packages/<vendor>/<package>/
  2. Add path repository to composer.json:
{
    "repositories": [{
        "type": "path",
        "url": "packages/<vendor>/<package>",
        "options": { "symlink": true }
    }]
}
  1. This allows patching the vulnerability locally without breaking API changes

Report Format

Present findings as:

## Security Audit Report - [Project Name]

### CRITICAL
- [Findings that need immediate action]

### HIGH
- [Findings that should be fixed soon]

### MEDIUM
- [Findings to address in next sprint]

### LOW
- [Recommendations for improvement]

### AUTO-FIXED
- [List of hardening applied]

### ACTION ITEMS
1. [ ] Rotate all credentials in .env
2. [ ] Kill any running miner processes
3. [ ] Review sudoers configuration
4. [ ] Deploy .htaccess changes to production
5. [ ] Monitor access logs for 48 hours

Common Attack Chain Reference

Based on real incidents, this is the typical attack flow:

1. ENTRY: Path traversal via vulnerable package (e.g., intervention/image v2)
   → Upload PHP webshell to storage/public directory

2. EXECUTION: Web server executes uploaded .php file
   → Because no .htaccess blocks PHP in storage dirs

3. DATA THEFT: Webshell reads .env file
   → Gets DB credentials, API keys (SendGrid, AWS, Stripe, etc.)

4. LATERAL MOVEMENT: Read .env from other projects on same server
   → Shared server = all projects compromised

5. PERSISTENCE: Install crypto miner + cron job
   → guard.sh / wp-admin.php pattern: download xmrig, auto-restart

6. ABUSE: Use stolen API keys
   → Send phishing emails via SendGrid
   → Access cloud resources via AWS keys

Important Notes

  • NEVER output actual credential values - only indicate what types exist
  • Always ask before applying fixes that could have breaking changes
  • Storage .htaccess and public .htaccess hardening are ALWAYS safe to apply
  • When in doubt, report and let the user decide
  • This skill is designed for defensive security only
Installs
14
GitHub Stars
5
First Seen
Mar 26, 2026