Quick security truth bomb: almost every PHP vulnerability you read about isn’t really in PHP itself. It’s in someone’s plugin. Someone’s theme. Someone’s “we’ll patch that later” code. And almost every Web Application Firewall sits on the outside of the building, sniffing HTTP traffic, watching for trouble. Which is great, right up until the attacker’s payload is encoded in base64-rot13-spelled-backwards and your WAF shrugs and lets it through.
That’s where PHP-Snuffleupagus earns its long ridiculous name. It’s a PHP extension that adds interpreter-level security hardening — every function call, every variable, every cookie passes through it. An attacker can fool your network. They cannot fool the PHP interpreter, because Snuffleupagus is inside it. This is PHP security hardening at the deepest possible layer in your stack, and it’s the layer almost no one bothers with.
Think of it as a bouncer who lives in your actual kitchen rather than at the club door. Even if someone climbs in through a window, they still can’t reach the stove without going through her. And honestly? She is not going to let them.

This post is the why. If you want the full installation walkthrough with the latest rules for PHP 8.5, head over to our complete PHP Snuffleupagus tutorial — this one explains what it does and why you want it. They pair nicely.
What PHP-Snuffleupagus Actually Blocks
- Dangerous function calls — system, exec, eval, shell_exec, passthru, proc_open. These are the functions an attacker reaches for the second they get code execution on your box. Snuffleupagus blocks them inside the PHP interpreter, before they ever get to run.
- SQL injection prevention — pattern-matches argument values that look like SQL injection attempts after all the framework-level escaping has happened. Catches the cases your ORM missed.
- XSS in echoed output — flags suspicious strings on their way to
echoorprint, including content that’s been through partial sanitisation. - Type juggling exploits — PHP’s famously bizarre loose comparison (yes, “0e12345” == “0” really is true) has been used to bypass password hashing more times than anyone wants to admit. Snuffleupagus enforces strict comparisons in sensitive code paths.
- Unsafe file uploads — runs a validation script before PHP processes any upload, so a PHP file disguised as cat.jpg never even gets a chance.
- Deserialization attacks — unserialize on untrusted input is the gateway drug to remote code execution. Disable it surgically per context.
- Cookie security flags — auto-enforces Secure, HttpOnly, and SameSite on every cookie your app sets, even if your sloppy plugin forgot.
- HTTP header injection — blocks newlines and other control characters from sneaking into HTTP response headers.
PHP-Snuffleupagus vs ModSecurity: Why You Want Both
“I already run ModSecurity on NGINX. Do I really need this too?” Honestly, yes. They’re not competitors — they live on different floors of the building and watch for completely different things.
| ModSecurity (NGINX WAF) | PHP-Snuffleupagus | |
|---|---|---|
| Where it runs | NGINX worker process, at the HTTP layer | Inside the PHP interpreter, in PHP-FPM workers |
| What it can see | Raw HTTP headers, URL, request body | Every PHP function call, its arguments, return values |
| What it blocks | Malicious HTTP patterns (SQLi in URL, XSS in form) | Dangerous functions, type juggling, cookie misuse |
| How easy to bypass | Encoding tricks, HTTP-layer obfuscation | Very hard — by the time PHP runs, the payload is already decoded |
| Performance cost | ~1-3% per request (CRS active) | Under 1% per request |
The right answer is to run both. ModSecurity is the door bouncer, screening obvious trouble before it ever reaches your PHP. Snuffleupagus is the kitchen bouncer, watching what PHP is allowed to actually do if anything slips through. This is what security professionals mean when they say “defence in depth” — multiple, independent layers that don’t share a single failure mode.
Need ModSecurity too? Our ModSecurity + OWASP CRS guide for NGINX walks through that side of the equation.
Installing PHP-Snuffleupagus on Debian and Ubuntu
PHP-Snuffleupagus packages are available from the myguard repository for PHP 7.0 through 8.5 on Debian and Ubuntu. One package per PHP version, so you can hold off updating your legacy app while still hardening the new ones:
# Add the myguard repository (if you haven't already)
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] \
/ stable main" \
| sudo tee /etc/apt/sources.list.d/myguard.list
sudo apt update
# Install for your PHP version (replace 8.3 with yours)
sudo apt install php8.3-snuffleupagus
# Verify the extension loaded
php-fpm8.3 -m | grep snuffleupagus
# Restart PHP-FPM to activate it
sudo systemctl restart php8.3-fpm
Supported PHP versions: 7.0, 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5. New to the myguard repository? Add it in under a minute.
Configuration: The Rules That Actually Matter
The config lives at /etc/php/8.3/fpm/conf.d/snuffleupagus.ini and points at rule files in /etc/snuffleupagus/. The first rule of Snuffleupagus club: start in simulation mode. Log what Snuffleupagus would block, find your false positives, then flip to enforcement. Skip this step and you’ll have a very lively Slack channel.
Block Dangerous Functions in Two Phases
# Phase 1 — simulation only (logs, never blocks)
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();
# Phase 2 — once the log is clean, flip .simulation() to .drop()
sp.disable_function.function("system").drop();
Enforce Cookie Security Flags
# Force Secure + SameSite on session cookies,
# even if your app code forgot to set them.
sp.cookie.name("PHPSESSID").samesite("strict").secure();
sp.cookie.name("wordpress_logged_in*").samesite("lax").secure();
Validate Every File Upload
# Run a validation script — non-zero exit rejects the upload
sp.upload_validation.script("/usr/bin/check-upload.sh").drop();
#!/bin/bash
# /usr/bin/check-upload.sh — block PHP files masquerading as images
file "$1" | grep -qi php && exit 1
exit 0
Per-Pool Rules for Multi-Tenant Servers
Running multiple WordPress sites (or a legacy app next to a new one) on the same PHP-FPM? Apply different rule sets per pool:
; /etc/php/8.3/fpm/pool.d/myapp.conf
php_admin_value[snuffleupagus.config] = /etc/snuffleupagus/myapp.rules
Watch the Log Like It’s the Bake-Off Final
tail -f /var/log/snuffleupagus.log
Every event — blocked or simulated — is logged with the rule that triggered, the function called, the file path, and a stack trace. This log is how you tune. Skip the simulation phase and you skip your only chance to catch false positives before your customers do.

Frequently Asked Questions
Does PHP-Snuffleupagus work with WordPress?
Yes, but with care. WordPress and especially its plugin ecosystem use a remarkably wide set of PHP functions. Always start with .simulation() mode, watch the log, whitelist legitimate function calls, then flip to .drop(). The Snuffleupagus project ships a WordPress-tuned starter rule set on GitHub.
Will Snuffleupagus break my application?
It can, which is exactly why simulation mode exists. Begin with everything set to .simulation(), let it run for a few days, read the log, whitelist real function calls your app legitimately makes, then enforce. Jumping straight to .drop() on a live site is how you get 2am phone calls.
Can I run PHP-Snuffleupagus and ModSecurity at the same time?
Yes, and you absolutely should. They operate at completely different layers — ModSecurity lives in the NGINX worker, Snuffleupagus lives inside PHP-FPM — and they don’t interfere with each other. This is the textbook defence-in-depth setup.
Does PHP-Snuffleupagus affect performance?
Barely. Rules are evaluated at function call time, not on every opcode. For typical PHP-FPM workloads the overhead is under 1% of request time — well below the noise floor of normal traffic variance.
What PHP versions are supported?
PHP 7.0 through 8.5 are packaged in the myguard repository. Install the package matching your PHP version (for example php8.5-snuffleupagus). Multiple PHP versions can happily coexist on the same server with independent rule sets per pool.
What is PHP type juggling and why is it dangerous?
PHP’s loose equality (==) has historical quirks: ‘0e12345’ == ‘0’ returns true because both strings are interpreted as floating-point zero in scientific notation. Attackers have used this to bypass password-hash comparisons that used == instead of ===. Snuffleupagus can enforce strict comparisons in sensitive contexts with sp.type_juggling.enable().
Where is the full tutorial with PHP 8.5 rules?
Our complete PHP Snuffleupagus tutorial for PHP 8.5 walks through every rule, every recommended setting, and includes a tested WordPress configuration you can drop straight in.
Related Posts
- PHP Snuffleupagus Tutorial — Harden PHP-FPM on Debian and Ubuntu (2026) — the full hands-on walkthrough with PHP 8.5 rules.
- How to Install ModSecurity and OWASP CRS on NGINX — the HTTP-layer companion to your interpreter-layer hardening.
- WordPress NGINX + PHP-FPM Configuration Guide — pool tuning, FastCGI caching and Redis, all secured underneath.
- NGINX and Angie Expert Guide — the wider performance and security stack this fits inside.