Hardening PHP with PHP-Snuffleupagus: Block SQL Injection, XSS and Dangerous Functions Inside PHP-FPM

Here’s a fun security fact: most PHP application vulnerabilities aren’t in PHP itself — they’re in your code or your plugins. And most WAFs (Web Application Firewalls) sit at the HTTP layer, sniffing requests for suspicious patterns. That works okay. But what if the attacker’s payload gets through anyway? What if it’s encoded weirdly, or the WAF has a blind spot?

That’s where PHP-Snuffleupagus comes in. It’s a PHP extension that adds a security layer inside PHP itself — at the interpreter level, where every function call happens, every variable gets read, and every cookie gets set. An attacker can trick your WAF. They can’t trick the PHP interpreter. Snuffleupagus runs inside it.

Think of it as a bouncer who lives in your kitchen instead of at the front door. Even if someone sneaks in through the window, they still can’t touch the stove.

PHP-Snuffleupagus PHP-FPM security hardening — blocking dangerous functions at interpreter level
PHP-Snuffleupagus works inside the PHP interpreter — a security layer no HTTP-level WAF can match

What Does PHP-Snuffleupagus Actually Block?

  • Dangerous function callssystem(), exec(), eval(), shell_exec(), passthru(). If your app gets code-injected, these are the functions the attacker wants. Snuffleupagus blocks them at the interpreter, before they run.
  • SQL injection and XSS patterns — detected in function arguments before they reach your database or output.
  • Type juggling exploits — PHP’s famously weird == behaviour ("0e12345" == "0" is true!) can bypass password checks. Snuffleupagus enforces strict comparisons.
  • Unsafe file uploads — validate uploads with a script before PHP processes them. Block PHP files disguised as images.
  • Deserialization attacks — PHP’s unserialize() is a classic attack vector. Disable it for untrusted input.
  • Cookie security — enforce Secure, HttpOnly, and SameSite flags on every cookie your app sets, even if your app code forgot.

PHP-Snuffleupagus vs ModSecurity: Different Layers, Both Useful

People often ask: “I already have ModSecurity WAF on NGINX. Do I need Snuffleupagus too?” Yes — they’re complementary, not competing.

ModSecurity (NGINX WAF)PHP-Snuffleupagus
Where it runsNGINX process, HTTP layerPHP interpreter, inside PHP-FPM
What it seesRaw HTTP headers, URL, request bodyPHP function calls, arguments, variables
What it blocksMalicious HTTP patterns (SQLi in URL, XSS in form)Dangerous functions, type juggling, bad cookies
Bypass riskEncoding tricks, HTTP-level obfuscationVery hard to bypass — runs inside the interpreter

Run both. ModSecurity filters bad HTTP traffic before it reaches PHP. Snuffleupagus controls what PHP is allowed to do if something gets through. Defence in depth — the thing security people keep saying that actually makes sense here.

Installation

PHP-Snuffleupagus is available from the myguard repository for PHP 7.0 through 8.4 on Debian and Ubuntu:

# Add the myguard repository (if not already done)
wget -qO- https://deb.myguard.nl/gpg.key 
  | gpg --dearmor > /usr/share/keyrings/myguard-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/myguard-archive-keyring.gpg] 
  https://deb.myguard.nl stable main" 
  | tee /etc/apt/sources.list.d/myguard.list
apt update

# Install for your PHP version
apt install php8.3-snuffleupagus

# Verify it loaded
php-fpm8.3 -m | grep snuffleupagus

# Restart PHP-FPM
systemctl restart php8.3-fpm

New to the myguard repository? Follow the setup guide to add it in under a minute.

Replace 8.3 with your PHP version. Supported: 7.0, 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, 8.4.

Configuration: The Good Stuff

The config lives at /etc/php/8.3/fpm/conf.d/snuffleupagus.ini and references rule files at /etc/snuffleupagus/default.rules. The golden rule: start with simulation mode, not blocking. Log what Snuffleupagus would block, tune out false positives, then switch to enforcement.

Block Dangerous Functions

# Simulation mode first (logs but doesn't block)
sp.disable_function.function("system").simulation();
sp.disable_function.function("exec").simulation();
sp.disable_function.function("eval").simulation();
sp.disable_function.function("shell_exec").simulation();
sp.disable_function.function("passthru").simulation();
sp.disable_function.function("proc_open").simulation();
sp.disable_function.function("unserialize").simulation();

# Once confirmed no false positives: switch .simulation() to .drop()
sp.disable_function.function("system").drop();

Enforce Cookie Security Flags

# Force Secure + SameSite on session cookies
# Catches cookies your app sets without proper flags
sp.cookie.name("PHPSESSID").samesite("strict").secure();
sp.cookie.name("wordpress_logged_in*").samesite("lax").secure();

Block PHP File Uploads

# Validate uploads with a script (exit non-zero to reject)
sp.upload_validation.script("/usr/bin/check-upload.sh").drop();
#!/bin/bash
# /usr/bin/check-upload.sh
# Reject PHP files disguised as images
file "$1" | grep -qi php && exit 1
exit 0

Per-Pool Rules (Different Rules Per Site)

Apply different rule sets per PHP-FPM pool. Strict rules for one legacy app, relaxed rules for a modern one on the same server:

; /etc/php/8.3/fpm/pool.d/myapp.conf
php_admin_value[snuffleupagus.config] = /etc/snuffleupagus/myapp.rules

Monitor the Log

tail -f /var/log/snuffleupagus.log

Each blocked (or simulated) event is logged with the rule that triggered it, the function called, and the arguments. Use this to tune your rules and catch false positives before going into enforcement mode. Don’t skip this step — seriously.

PHP logo — PHP-Snuffleupagus secures PHP-FPM at the interpreter level
Snuffleupagus works inside PHP-FPM — pair it with ModSecurity in NGINX for full-stack defence

Frequently Asked Questions

Does PHP-Snuffleupagus work with WordPress?
Yes, with care. WordPress and its plugins use a broad set of PHP functions. Always start with .simulation() mode to log what would be blocked, identify false positives, then switch to .drop(). The official docs include a WordPress-specific rule set as a starting point.
Will Snuffleupagus break my application?
Possibly — which is exactly why simulation mode exists. Start with .simulation(), read the logs, whitelist legitimate function calls, then enforce. Jumping straight to .drop() on a live site is how you get 2am emergency calls.
Can I run PHP-Snuffleupagus and ModSecurity at the same time?
Yes. They operate at completely different layers and don’t interfere with each other. ModSecurity is in the NGINX process; Snuffleupagus is inside PHP-FPM. Both can be active simultaneously and complement each other perfectly.
Does PHP-Snuffleupagus affect performance?
Minimally. Most rules are checked at function call time, not on every opcode. For a typical PHP-FPM application the overhead is under 1% of request time — completely imperceptible to users.
What PHP versions are supported?
PHP 7.0 through 8.4. Install the package matching your PHP version: php7.4-snuffleupagus, php8.1-snuffleupagus, etc. Multiple versions can coexist on the same server.
What is type juggling and why is it dangerous in PHP?
PHP’s loose comparison (==) has famous quirks: ‘0e12345’ == ‘0’ is true because both are treated as floating-point zero in scientific notation. Attackers exploit this to bypass password hash comparisons. Snuffleupagus enforces strict comparisons in sensitive contexts with sp.type_juggling.enable().

Related Posts