Fetch Metadata write-request observation
Logging only, enabled by default. No new requests are blocked. Existing Origin validation, CSRF tokens, cross-origin exemptions, authentication, response headers/body/status and caching remain unchanged. Future enforcement requires a separate reviewed change.
What is observed
At the start of CsrfComponent::startup, attempt to log requests whose effective Cake method is not GET/HEAD/OPTIONS and whose Sec-Fetch-Site is not exactly same-origin. This includes absent, empty and unknown values as well as same-site, cross-site and none.
Observation precedes the existing Origin/token checks and AllowCrossOriginRequests exemption. Consequently, intentional cross-origin APIs/payment returns and requests subsequently rejected by CSRF are included. Safe effective methods and exact same-origin requests do not open the diagnostic log. Method overrides follow Cake's interpretation, consistently with the existing CSRF guard; this is not a separate raw wire-method policy.
Coverage is controller requests that reach this component. Static files, FastCGI cache hits, earlier nginx/dispatcher/authentication rejections and endpoints outside this lifecycle are not covered. This is not an ingress access log or a count of every HTTP request.
Output and privacy
Dedicated app/tmp/logs/fetch_site_shadow.log, using MyFileLog's timestamp/Info prefix followed by one JSON object. Each record contains:
- UTC timestamp and
fetch_site_shadowevent; - canonical, source-defined controller class/action (not URL parameters);
- effective HTTP method;
- category-only
sec_fetch_site,sec_fetch_mode,sec_fetch_dest; origin_kind:missing,null,allowlisted,same-host, orother;- action declarations
cross_origin_exemptandcsrf_token_required.
Missing Fetch Metadata values are <missing>; unknown values/nonstandard methods are <other>. An empty site header is <other>, not same-origin. Origin categories describe the existing guard: same-host does not imply a full scheme/port match. The token boolean reflects the declaration, not whether a token was supplied or valid; the existing cross-origin exemption skips token checking.
No raw URL/path arguments, query string, body, Origin/Referer, cookies, credentials, user/customer IDs, IPs, user agents or request IDs are written. The log does not inspect response bodies or record final response status. A candidate record is not proof of a successful business action: some requests are already rejected by the existing guards.
Every matching request attempts a write; there is no per-minute sampling/deduplication. A nonblocking lock serializes writes/rotation. Contention or unwritable storage drops the record rather than waiting or failing a business request. Logging exceptions are swallowed without Sentry capture. There are no Redis, database or network calls. Ordinary filesystem I/O still adds some overhead.
Disk usage is bounded by a 10 MiB current file and at most two rotations (approximately 30 MiB plus a final record). The separate local app/tmp/locks/fetch_site_shadow.lock holds no request data. Log and lock creation use mode 0600.
Disable via existing application configuration if necessary:
There is deliberately no enforcement switch.
Deciding whether to block later
Group candidates by controller/action, method, site, Origin category and exemptions. Separate browser-session writes from machine integrations, webhooks, payment returns and public cross-origin APIs. same-site is not equivalent to same-origin; none and missing metadata are not proof of a legitimate write. Headers are browser-origin signals, not API authentication.
Observe normal WWK and TP traffic, including admin/partner flows and rare external returns. Do not replay customer actions or payment callbacks to generate evidence. The bounded log can lose history through rotation/contention, so absence is not proof of zero usage. Use existing access/application logs read-only when investigating a route; do not interpret candidate counts as accepted-write counts.
Before any block, define exceptions/fallbacks and tests explicitly. Keep existing sensitive-action tokens: Origin/Fetch Metadata cannot distinguish legitimate markup from injected same-origin HTML. Rollout/deployment and any blocking policy remain separate approvals.