Supamask is a lightweight PHP security gate that protects an application before its origin code runs. It combines route challenges, disposable URLs, proof-of-work, IP and CIDR rules, bot detection, referrer controls, and optional IP intelligence behind one decision model:
DENY > CHALLENGE > ALLOW
Hard-denied traffic is stopped before challenge creation, proof-of-work, disposable-entry handling, or application execution.
- Route challenges with session verification
- Disposable, expiring, single-use entry URLs and replay protection
- Query-string preservation through the challenge flow
- Server-verified proof-of-work
- Polymorphic challenge presentation and honeypot markup
- Exact IP, IPv4/IPv6 CIDR, AntiRed, and User-Agent bot blocking
- Optional VPN, ASN, and ISP exclusions through IPinfo or ipapi.is
- Safe hostname-based referrer blocking
- Configurable DENY responses and optional JSON-lines request logging
- PHP 8.1+
- Composer
composer require devgonerogue/supamaskConfigure your web server to send protected, disposable, and challenge routes to the PHP front controller.
Place Supamask at the start of your front controller, before application output or protected work:
<?php
require __DIR__ . '/vendor/autoload.php';
use Supamask\Supamask;
Supamask::boot([
'challenge' => [
'middleware' => ['enabled' => true],
'protection' => [
'enabled' => true,
'paths' => ['/account', '/checkout'],
],
'proof_of_work' => [
'enabled' => true,
'difficulty' => 16,
],
],
'ip_blocking' => [
'enabled' => true,
'antired' => false,
'rules' => ['203.0.113.10', '198.51.100.0/24'],
],
'bot_blocking' => [
'enabled' => true,
'antired' => false,
'signatures' => ['ExampleBadBot'],
],
]);
// Runs only when Supamask allows the request.
$user = $_GET['user'] ?? 'World';
echo 'Hello, ' . htmlspecialchars($user, ENT_QUOTES, 'UTF-8') . '!';Supamask::boot() sends a Supamask response and terminates execution for DENY or CHALLENGE decisions. Origin code therefore runs only on ALLOW.
IP / CIDR / AntiRed / bot / IP intelligence / referrer
│
┌────────┴────────┐
│ │
DENY not denied
│ │
▼ ▼
response disposable entry / challenge policy
│
CHALLENGE or ALLOW
A blocked IP, bot, VPN, excluded ASN/ISP, or blocked referrer can never receive a challenge instead of a denial, including for an active disposable URL.
Optional controls are independently configurable:
Supamask::boot([
'ip_blocking' => [
'enabled' => true,
'antired' => true,
'rules' => ['203.0.113.10', '2001:db8:1234::/48'],
],
'bot_blocking' => [
'enabled' => true,
'antired' => true,
'signatures' => ['ExampleBot'],
],
'challenge' => [
'enabled' => true,
'middleware' => ['enabled' => true],
'protection' => [
'enabled' => true,
'paths' => ['/members/*'],
'exclude_paths' => ['/health'],
],
'ttl' => 300,
'verification_ttl' => 1800,
'proof_of_work' => [
'enabled' => true,
'difficulty' => 16,
'ttl' => 300,
],
],
'routing' => [
'root' => ['behavior' => 'allow'], // allow or challenge
],
'disposable' => [
'enabled' => true,
'single_use' => true,
'ttl' => 900,
'slug_length' => 12,
],
]);The default DENY response is 403. To redirect denied traffic, supply a trusted absolute HTTP(S) destination:
'responses' => [
'deny' => [
'action' => 'redirect',
'redirect' => 'https://example.com/access-denied',
'redirect_status' => 302,
],
],Supamask never reads this destination from request parameters. Relative, protocol-relative, malformed, and non-HTTP(S) destinations are rejected.
Referrer matching is hostname-based, case-insensitive, and includes subdomains:
'block_referrers' => true,
'referrer_blocklist' => ['badsite.com'],
'block_missing_referrer' => false,badsite.com, www.badsite.com, and sub.badsite.com match. badsite.com.evil.example does not. Missing referrers are allowed unless block_missing_referrer is enabled.
IP intelligence is disabled by default. Enable it with provider credentials:
'block_vpn' => true,
'detect_isp' => true,
'isp_exclusions' => ['AS14061', 'DigitalOcean'],
'ip_intelligence' => [
'provider' => 'ipapi.is', // or 'ipinfo'
// ipapi.is supports anonymous single-IP lookups; a key is optional.
'token' => getenv('SUPAMASK_IPAPI_IS_KEY') ?: '',
'timeout' => 2,
'cache_ttl' => 3600,
'cache_directory' => __DIR__ . '/../storage/ip-intelligence',
],When VPN/ASN/ISP intelligence is disabled, no provider credentials are required and no external lookup is made. IPinfo requires a token (or SUPAMASK_IPINFO_TOKEN) when enabled; ipapi.is supports its documented anonymous single-IP endpoint, with an optional SUPAMASK_IPAPI_IS_KEY.
Provider failures are unknown intelligence—not confirmed malicious traffic—unless you explicitly set ip_intelligence.fail_closed to true.
Disposable entries accept local destinations only, support expiry and optional single-use consumption, and return a successfully verified visitor to the exact stored application destination, including its query string.
Application parameters remain application data. For example, ?redirect=https://evil.example is preserved for the application; it is never treated as Supamask redirect configuration.
Logging is disabled by default. Enable it explicitly:
'logging' => [
'enabled' => true,
'directory' => __DIR__ . '/../storage/logs',
'include_query_string' => false,
],Each line in bouncer.log is JSON containing timestamp, IP, method, URI, decision, and reason. Query strings are excluded by default because they can contain sensitive data. Logging is observational: a logging failure never changes a security decision.
Use a directory outside the public web root in production. Supamask does not expose logs through its routing.
Fresh challenges vary presentation identifiers, copy, and layout while preserving the same server-side verification contract. When enabled, proof-of-work is solved in the browser and verified by the server before the challenge is consumed.
composer testThe suite covers decision precedence, disposable lifecycle, replay prevention, proof-of-work, query preservation, IP intelligence, referrer boundaries, logging, and presentation behavior.
- Keep Supamask at the start of the front controller.
- When deployed behind a proxy, configure its trusted address or CIDR in
proxy.trusted; Supamask never trusts forwarded IP headers from an untrusted peer. - Use HTTPS and secure session-cookie settings.
- Keep logs and IP-intelligence caches outside the public web root.
MIT.