diff --git a/AGENTS.md b/AGENTS.md index 23557c5..d36d40e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,7 +28,7 @@ All of `src/`, namespace `RenzoFranceschini\GuardCore`: - `Routing/`: `RouteConfig` (per-route bypasses, rate limits, required headers, auth, time windows) and `RouteResolver` (resolves by `RequestState::$guardRouteId`). - `Logging/`: request/suspicious logging with redaction (`LogRedactor`). -Known surface gaps (fail closed or documented, never silently no-op): no route registry on the `GuardEngine` facade (route configs resolve only when a caller wires them), fixed `Too many requests` 429 body (not tunable via `customErrorResponses`), in-process auto-ban violation counters, address-header ssrf exclusion delegated to `logSensitiveHeaders`. +Known surface gaps (fail closed or documented, never silently no-op): no route registry on the `GuardEngine` facade (route configs resolve only when a caller wires them), fixed `Too many requests` 429 body (not tunable via `customErrorResponses`), in-process auto-ban violation counters. ## Boundary Rules diff --git a/examples/advanced_app/src/config.php b/examples/advanced_app/src/config.php index 661a969..b91850c 100644 --- a/examples/advanced_app/src/config.php +++ b/examples/advanced_app/src/config.php @@ -35,17 +35,6 @@ function advanced_int_env(string $key, int $fallback): int return (int) $raw; } -/** Address headers the Python engine skips when scanning for ssrf patterns. */ -function advanced_address_headers(): array -{ - return [ - 'host', 'origin', 'via', 'x-forwarded-for', 'x-forwarded-host', - 'x-forwarded-proto', 'x-real-ip', 'x-client-ip', 'x-cluster-client-ip', - 'cf-connecting-ip', 'true-client-ip', 'fly-client-ip', - 'x-envoy-external-address', - ]; -} - function advanced_config(): SecurityConfig { return new SecurityConfig( @@ -82,9 +71,9 @@ function advanced_config(): SecurityConfig ], // Detection: every category, default detector tuning. enablePenetrationDetection: true, - // See advanced_address_headers() above: without this, nginx's - // forwarded headers get flagged as ssrf attempts. - logSensitiveHeaders: advanced_address_headers(), + // The engine skips the ssrf category for nginx's forwarded headers + // (host, x-forwarded-for, x-real-ip, ...) by default; use + // excludedDetectionHeaders for your own address-carrying headers. // Edge filters. blockedUserAgents: ['badbot', 'evil-crawler', 'sqlmap'], blockCloudProviders: advanced_split_csv(getenv('BLOCK_CLOUD_PROVIDERS') ?: ''), diff --git a/examples/simple_app/README.md b/examples/simple_app/README.md index 6b279a2..c726e9c 100644 --- a/examples/simple_app/README.md +++ b/examples/simple_app/README.md @@ -62,13 +62,7 @@ curl -i http://localhost:8080/ ## A note on address headers -The Python engine skips ssrf scanning for address headers (`host`, -`x-forwarded-for`, `x-real-ip`, ...) automatically. This PHP port does not -apply that built-in exclusion yet and has no dedicated excluded-detection- -headers knob; it does skip headers listed in `logSensitiveHeaders` during -detection scanning, so `index.php` routes the address headers through that -field. Without it, a plain `Host: localhost` request is flagged as an ssrf -attempt. +The engine skips the `ssrf` category for the proxy identity headers (`host`, `x-forwarded-for`, `x-real-ip`, `cf-connecting-ip`, `forwarded`, ...) by default, so a plain `Host: localhost` request is not flagged and `index.php` needs no workaround. Every other category still scans those headers. Pass `excludedDetectionHeaders` to extend the set with your own address-carrying headers, and `excludedSemanticDetectionHeaders` to keep a header out of the semantic analyzer only. ## Configuration knobs demonstrated diff --git a/examples/simple_app/index.php b/examples/simple_app/index.php index e744a9c..2d0c965 100644 --- a/examples/simple_app/index.php +++ b/examples/simple_app/index.php @@ -26,18 +26,6 @@ require __DIR__ . '/../../vendor/autoload.php'; -// Address headers the Python engine skips when scanning for ssrf patterns. -// This port has no dedicated excluded-detection-headers knob yet; it does -// skip headers listed in logSensitiveHeaders during detection scanning, so -// we route the address headers through it. Without this, a plain -// "Host: localhost" request is flagged as an ssrf attempt. -const ADDRESS_HEADERS = [ - 'host', 'origin', 'via', 'x-forwarded-for', 'x-forwarded-host', - 'x-forwarded-proto', 'x-real-ip', 'x-client-ip', 'x-cluster-client-ip', - 'cf-connecting-ip', 'true-client-ip', 'fly-client-ip', - 'x-envoy-external-address', -]; - /** * Engine holder. Runtimes that keep the process alive across requests * (worker mode under FrankenPHP/RoadRunner-style loops) reuse the instance @@ -73,8 +61,10 @@ function simple_engine(): GuardEngine autoBanDuration: 300, // Penetration detection: all categories, default thresholds. enablePenetrationDetection: true, - // See ADDRESS_HEADERS above. - logSensitiveHeaders: ADDRESS_HEADERS, + // The engine already skips the ssrf category for the proxy identity + // headers (host, x-forwarded-for, x-real-ip, ...), so no header opt-out + // is needed here. Add excludedDetectionHeaders for your own + // address-carrying headers. // Blocked user agents (regex patterns). blockedUserAgents: ['badbot', 'evil-crawler', 'sqlmap'], // Custom block bodies, keyed by status code.