@@ -81,38 +81,40 @@ def call(env)
8181 ::Rails . logger . warn ( security_log )
8282
8383 [ FORBIDDEN_STATUS , IP_SPOOF_HEADERS . dup , [ IP_SPOOF_HTML ] ]
84- rescue ::ActionController ::InvalidAuthenticityToken => invalid_auth_token_error
85- # Create a security log for CSRF error
86- security_log = Log ::Security ::CSRFViolation . new (
87- path : request . path ,
88- http_method : request . method ,
89- source_ip : request . remote_ip ,
90- user_agent : request . user_agent ,
91- referer : request . referer ,
92- request_id : request . request_id ,
93- message : invalid_auth_token_error . message ,
94- timestamp : Time . now
95- )
96- LogStruct . error ( security_log )
97-
98- # Report to error reporting service and/or re-raise
99- context = extract_request_context ( env , request )
100- LogStruct . handle_exception ( invalid_auth_token_error , source : Source ::Security , context : context )
101-
102- # If handle_exception raised an exception then Rails will deal with it (e.g. config.exceptions_app)
103- # If we are only logging or reporting these security errors, then return a default response
104- [ FORBIDDEN_STATUS , CSRF_HEADERS . dup , [ CSRF_HTML ] ]
10584 rescue => error
106- # Extract request context for error reporting
107- context = extract_request_context ( env , request )
108-
109- # Create and log a structured exception with request context
110- exception_log = Log . from_exception ( Source ::Rails , error , context )
111- LogStruct . error ( exception_log )
112-
113- # Re-raise any standard errors to let Rails or error reporter handle it.
114- # Rails will also log the request details separately
115- raise error
85+ if csrf_error? ( error )
86+ # Create a security log for CSRF error
87+ security_log = Log ::Security ::CSRFViolation . new (
88+ path : request . path ,
89+ http_method : request . method ,
90+ source_ip : request . remote_ip ,
91+ user_agent : request . user_agent ,
92+ referer : request . referer ,
93+ request_id : request . request_id ,
94+ message : error . message ,
95+ timestamp : Time . now
96+ )
97+ LogStruct . error ( security_log )
98+
99+ # Report to error reporting service and/or re-raise
100+ context = extract_request_context ( env , request )
101+ LogStruct . handle_exception ( error , source : Source ::Security , context : context )
102+
103+ # If handle_exception raised an exception then Rails will deal with it (e.g. config.exceptions_app)
104+ # If we are only logging or reporting these security errors, then return a default response
105+ [ FORBIDDEN_STATUS , CSRF_HEADERS . dup , [ CSRF_HTML ] ]
106+ else
107+ # Extract request context for error reporting
108+ context = extract_request_context ( env , request )
109+
110+ # Create and log a structured exception with request context
111+ exception_log = Log . from_exception ( Source ::Rails , error , context )
112+ LogStruct . error ( exception_log )
113+
114+ # Re-raise any standard errors to let Rails or error reporter handle it.
115+ # Rails will also log the request details separately
116+ raise error
117+ end
116118 end
117119 end
118120
@@ -146,6 +148,13 @@ def extract_request_context(env, request = nil)
146148 { error_extracting_context : error . message }
147149 end
148150
151+ sig { params ( error : StandardError ) . returns ( T ::Boolean ) }
152+ def csrf_error? ( error )
153+ error_name = error . class . name
154+ error_name == "ActionController::InvalidAuthenticityToken" ||
155+ error_name == "ActionController::InvalidCrossOriginRequest"
156+ end
157+
149158 sig { params ( configured_proxies : T . untyped ) . returns ( T . untyped ) }
150159 def normalized_trusted_proxies ( configured_proxies )
151160 if configured_proxies . nil? || ( configured_proxies . respond_to? ( :empty? ) && configured_proxies . empty? )
0 commit comments