PHP-Snuffleupagus is a PHP extension that adds a security layer to PHP-FPM — blocking SQL injection, XSS, dangerous function calls, and more at the interpreter level. It works with PHP 7.0 through 8.4 and is available via APT from the myguard repository.
Why use Snuffleupagus?
- Blocks SQL injection, XSS, type juggling and other common PHP vulnerabilities at the interpreter level — before your application code even runs
- Disables dangerous functions (
system(), exec(), eval() etc.) globally or per virtual host
- Detects and blocks request smuggling and serialization attacks
- Defines custom per-site security policies — stricter than any WAF at the HTTP layer
- Works alongside ModSecurity and NAXSI for defense in depth
Snuffleupagus vs ModSecurity: interpreter-level vs HTTP-level
system(), exec(), eval() etc.) globally or per virtual hostModSecurity and Snuffleupagus work at different layers of the stack and complement each other:
| ModSecurity (nginx WAF) | PHP-Snuffleupagus | |
|---|---|---|
| Where it runs | nginx process, inspects raw HTTP requests and responses | PHP interpreter, inspects function calls and variable values inside PHP |
| What it can see | HTTP headers, raw request body, URL, response body | All PHP function arguments, return values, superglobals, file operations, cookie values |
| What it can block | Malicious HTTP patterns (SQL in URL, XSS in form field) | Dangerous PHP functions being called, type juggling tricks, deserialization of untrusted data |
| Encrypted payloads | Cannot inspect encrypted body without TLS termination | Always sees the decrypted, parsed PHP values |
| Bypassed by | Encoding tricks, unusual HTTP patterns | Very difficult to bypass: rules apply at the interpreter, not the network |
| Configuration | Rule files (OWASP CRS) + nginx config | .rules files per PHP-FPM pool |
Run both: ModSecurity filters malicious HTTP traffic before PHP runs; Snuffleupagus enforces what PHP is allowed to do even if a payload gets through.
Installation
After adding the myguard repository:
apt-get update
apt-get install php8.3-snuffleupagus
Replace 8.3 with your PHP version (7.0 through 8.4 are supported).
Configuration
The main configuration file is created automatically at:
/etc/php/8.3/fpm/conf.d/snuffleupagus.ini
Edit it to enable rules:
nano /etc/php/8.3/fpm/conf.d/snuffleupagus.ini
The file references /etc/snuffleupagus/default.rules which contains the recommended rule set. Start with the defaults and tighten from there.
Verify the module is loaded
php-fpm8.3 -m | grep snuffleupagus
Restart PHP-FPM
systemctl restart php8.3-fpm
Key protections explained
Block dangerous PHP functions
php-fpm8.3 -m | grep snuffleupagussystemctl restart php8.3-fpm
Key protections explained
Block dangerous PHP functions
Functions like system(), exec(), and passthru() execute OS commands directly. An attacker who finds a code injection vulnerability can use them to run arbitrary commands on the server. Snuffleupagus blocks them at the interpreter level — even if the attacker injects PHP code, calling these functions results in a logged drop, not execution.
# in your .rules file
sp.disable_function.function("system").drop();
sp.disable_function.function("exec").drop();
sp.disable_function.function("passthru").drop();
sp.disable_function.function("eval").drop();
sp.disable_function.function("shell_exec").drop();
sp.disable_function.function("proc_open").drop();
Enforce cookie security flags
Without the Secure flag, session cookies can be transmitted over HTTP, allowing interception. Without SameSite, cookies are sent on cross-site requests, enabling CSRF. Snuffleupagus enforces these flags on every cookie your PHP application sets, regardless of whether the application code sets them correctly.
sp.cookie.name("PHPSESSID").samesite("strict").secure();
Block upload of PHP files
File upload vulnerabilities let attackers upload a PHP file disguised as an image and then execute it. Snuffleupagus can validate uploads with a custom script before PHP processes them. The script receives the temporary file path and exits non-zero to reject the upload.
sp.upload_validation.script("/usr/bin/check-upload.sh").drop();
A simple check-upload.sh that rejects PHP files:
#!/bin/bash
file "$1" | grep -qi php && exit 1
exit 0
Block PHP deserialization of untrusted data
PHP’s unserialize() is a frequent attack vector — passing a crafted serialized string can instantiate arbitrary objects and trigger __wakeup() or __destruct() methods. If your application does not use unserialize() on user input, disable it:
sp.disable_function.function("unserialize").drop();
Virtual-host level rules
Snuffleupagus can apply different rule sets per PHP-FPM pool. This lets you apply strict rules to a legacy application without breaking a modern one on the same server. Add to your pool config:
; /etc/php/8.3/fpm/pool.d/myapp.conf
php_admin_value[snuffleupagus.config] = /etc/snuffleupagus/myapp.rules
Type juggling protection
PHP’s loose comparison (==) has well-known type juggling quirks: "0e12345" == "0" is true because both are treated as scientific notation. Attackers exploit this to bypass password hash comparisons. Snuffleupagus can enforce strict comparisons in sensitive contexts:
sp.type_juggling.enable();
Monitor the log
tail -f /var/log/snuffleupagus.log
tail -f /var/log/snuffleupagus.logEach blocked event is logged with the rule that triggered it, the function called, and the arguments. Use this to tune rules and identify false positives before switching from simulation mode to drop mode.
Frequently asked questions
Does Snuffleupagus work with WordPress?
Yes, with care. WordPress and its plugins use a broad set of PHP functions. Start with simulation_mode for each rule (which logs but does not block) to identify which rules trigger false positives. The Snuffleupagus documentation includes a WordPress-specific rule set as a starting point.
Can I run Snuffleupagus and ModSecurity at the same time?
Yes — they operate at different layers and do not interfere with each other. ModSecurity filters HTTP traffic before it reaches PHP; Snuffleupagus enforces rules inside the PHP process. Running both provides defense in depth.
Will blocking eval() break my application?
It depends. Many PHP applications (including WordPress) use eval() in template engines, plugin loaders, or obfuscated code. Use .simulation() mode first: sp.disable_function.function("eval").simulation(); — this logs calls to eval() without blocking them, so you can assess the impact.
Which 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 system if you run multiple PHP-FPM versions.
Does Snuffleupagus affect PHP-FPM 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. The cookie and upload rules add negligible overhead.