diff --git a/docs/tutorial/configuration/security-config.md b/docs/tutorial/configuration/security-config.md index dd934771..79385fa1 100644 --- a/docs/tutorial/configuration/security-config.md +++ b/docs/tutorial/configuration/security-config.md @@ -58,7 +58,7 @@ New configuration fields for the enhanced Detection Engine: | `detection_monitor_history_size` | int | 1000 | Number of performance metrics to keep in history | | `detection_max_tracked_patterns` | int | 1000 | Maximum patterns to track for performance | | `detection_scan_body` | bool | True | Scan the request body during penetration detection; when False, detection is restricted to the URL path, query params, and headers | -| `excluded_detection_headers` | set[str] | `set()` | Header names to skip during penetration detection, merged with the built-in exclusions; matched case-insensitively | +| `excluded_detection_headers` | set[str] | `set()` | Header names to skip during penetration detection, merged with the built-in exclusions; matched case-insensitively. Skips semantic analysis only (useful for URL-bearing headers like `referer` and `origin` that trip `ssrf`); pattern-based checks still run | | `excluded_detection_params` | set[str] | `set()` | Query parameter names to skip during penetration detection (an OAuth `redirect_uri` that carries a loopback URL, for example); matched case-insensitively. Per route: `@guard_deco.detection_exclusion(params=...)` | | `excluded_detection_body_fields` | set[str] | `set()` | JSON body keys to skip during penetration detection, at any nesting depth, also applied to form and multipart text field names | | `detection_threat_score_threshold` | float | 1.0 | Anomaly score required to flag a request as a threat (0.0-10.0) | diff --git a/docs/tutorial/decorators/advanced.md b/docs/tutorial/decorators/advanced.md index a0e2674f..a9971b16 100644 --- a/docs/tutorial/decorators/advanced.md +++ b/docs/tutorial/decorators/advanced.md @@ -136,7 +136,7 @@ def authorize(redirect_uri: str): return {"status": "redirecting"} ``` -`headers` and `body_fields` take the same shape. The global equivalents are `excluded_detection_params`, `excluded_detection_headers` and `excluded_detection_body_fields` on `SecurityConfig`. +`headers` and `body_fields` take the same shape. The global equivalents are `excluded_detection_params`, `excluded_detection_headers` and `excluded_detection_body_fields` on `SecurityConfig`. Headers that carry URLs, such as `referer` and `origin`, are the usual header case: excluding one stops its semantic analysis but leaves the pattern-based checks running against it. ___ diff --git a/docs/tutorial/security/penetration-detection.md b/docs/tutorial/security/penetration-detection.md index 1fd56a52..e4be2b70 100644 --- a/docs/tutorial/security/penetration-detection.md +++ b/docs/tutorial/security/penetration-detection.md @@ -69,7 +69,16 @@ config = SecurityConfig( ) ``` -The same exists for headers and JSON body keys (`excluded_detection_headers`, `excluded_detection_body_fields`); names are matched case-insensitively, and body keys at any nesting depth. To limit the exclusion to one route, use the decorator instead of the global setting: +The same exists for headers and JSON body keys (`excluded_detection_headers`, `excluded_detection_body_fields`); names are matched case-insensitively, and body keys at any nesting depth. Headers carrying URLs are the usual header case: `referer` and `origin` hold full URLs and can trip the `ssrf` category on endpoints that legitimately receive them. + +```python +config = SecurityConfig( + enable_penetration_detection=True, + excluded_detection_headers={"referer", "origin"}, +) +``` + +Excluding a name stops the semantic analysis of that value; the pattern-based checks still run against it, so the header is not fully silenced. To limit the exclusion to one route, use the decorator instead of the global setting: ```python from guard import SecurityDecorator