CVE-2021-41083: Cross-Site Request Forgery (CSRF) (CWE-352)
value: Dada Mail is a web-based e-mail list management system. In affected versions a bad actor could give someone a carefully crafted web page via email, SMS, etc, that - when visited, allows them control of the list control panel as if the bad actor was logged in themselves. This includes changing any mailing list password, as well as the Dada Mail Root Password - which could effectively shut out actual list owners of the mailing list and allow the bad actor complete and unfettered control of your mailing list. This vulnerability also affects profile logins. For this vulnerability to work, the target of the bad actor would need to be logged into the list control panel themselves. This CSRF vulnerability in Dada Mail affects all versions of Dada Mail v11.15.1 and below. Although we know of no known CSRF exploits that have happened in the wild, this vulnerability has been confirmed by our testing, and by a third party. Users are advised to update to version 11.16.0.
CWE description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
CVSS v3 base score: 8.8
Published: 2021-09-20T22:15Z
Repository: https://github.com/justingit/dada-mail
Language: Perl
Files changed: dada/DADA/App.pm, dada/DADA/Profile/Session.pm, dada/DADA/Template/Widgets.pm, dada/templates/profile_home.tmpl, dada/templates/profile_login.tmpl
Commit date: 2021-09-19 18:02:02 -0600
Commit message: This adds CSRF protection to the profiles. 

Diff: diff --git a/dada/DADA/App.pm b/dada/DADA/App.pm
index e0ff5176..f33b536a 100755
--- a/dada/DADA/App.pm
+++ b/dada/DADA/App.pm
@@ -15084,18 +15084,15 @@ sub profile_login {
         if ( length( $ENV{QUERY_STRING} ) > 0 ) {
             $whole_url .= '?' . $ENV{QUERY_STRING};
         }
     }
 
-    if (   $DADA::Config::PROFILE_OPTIONS->{enabled} != 1) {
+    if ( $DADA::Config::PROFILE_OPTIONS->{enabled} != 1) {
         return $self->default();
 
     }
-
-    if ( $DADA::Config::PROFILE_OPTIONS->{enabled} != 1 ) {
-        return $self->default();
-    }
+	
     require DADA::Profile;
     ###
     my $all_errors = [];
     my $named_errs = {};
     my $errors     = $q->param('errors');
@@ -15107,26 +15104,32 @@ sub profile_login {
 
     require DADA::Profile::Session;
     my $prof_sess = DADA::Profile::Session->new;
 
     if ( $q->param('process') != 1 ) {
-
         if (   $prof_sess->is_logged_in( { -cgi_obj => $q } )
             && $q->param('logged_out') != 1 )
         {
             $self->header_type('redirect');
             $self->header_props(
                 -url => $DADA::Config::PROGRAM_URL . '/profile/' );
         }
         else {
-            my $scrn              = '';
+			my $scrn              = '';
             my $using_captcha     = 0;
 
             if ( $DADA::Config::PROFILE_OPTIONS->{enable_captcha} == 1 ) {
                 $using_captcha = can_use_Google_reCAPTCHA();
             }
 
+			my $auth_state;
+		    if ( $DADA::Config::DISABLE_OUTSIDE_LOGINS == 1 ) {
+		        require DADA::Security::SimpleAuthStringState;
+		        my $sast = DADA::Security::SimpleAuthStringState->new;
+		        $auth_state = $sast->make_state;
+		    }
+
             $scrn = DADA::Template::Widgets::wrap_screen(
                 {
                     -screen => 'profile_login.tmpl',
                     -with   => 'list',
                     -expr   => 1,
@@ -15165,10 +15168,13 @@ sub profile_login {
                         can_use_captcha => $using_captcha,
                         welcome         => scalar $q->param('welcome') || '',
                         removal         => scalar $q->param('removal') || '',
                         WHOLE_URL       => $whole_url,
 						
+		                auth_state      => $auth_state,
+						
+						
 						# This should probably be deprecated, as I'm handling this in 
 						# DADA::Template::Widgets, now
                         %{ DADA::Profile::feature_enabled() }
                     },
 
@@ -15178,23 +15184,24 @@ sub profile_login {
         }
     }
     else {
         my ( $status, $errors ) = $prof_sess->validate_profile_login(
             {
-                -email    => xss_filter( scalar $q->param('login_email') ),
-                -password => xss_filter( scalar $q->param('login_password') ),
+                -email      => xss_filter( scalar $q->param('login_email') ),
+                -password   => xss_filter( scalar $q->param('login_password') ),
+				-auth_state => xss_filter( scalar $q->param('auth_state') ),
 
             },
         );
 
         if ( $status == 1 ) {
             my $cookie = $prof_sess->login(
                 {
-                    -email => xss_filter( scalar $q->param('login_email') ),
-                    -password =>
-                      xss_filter( scalar $q->param('login_password') ),
-                },
+                    -email           => xss_filter( scalar $q->param('login_email') ),
+                    -password        => xss_filter( scalar $q->param('login_password') ),					
+                	-skip_validation => 1, 
+				},
             );
 
             #DEV: encoding?
             my $headers = {
                 -cookie  => [$cookie],
@@ -15395,22 +15402,35 @@ sub profile {
     }
 
     if (   $DADA::Config::PROFILE_OPTIONS->{enabled} != 1) {
         return $self->default();
     }
+	
+	
+	
 
     require DADA::Profile::Session;
     my $prof_sess = DADA::Profile::Session->new;
 
-    if ( $prof_sess->is_logged_in( { -cgi_obj => $q } ) ) {
-        my $email = $prof_sess->get( { -cgi_obj => $q } );
+    if ($prof_sess->is_logged_in( { -cgi_obj => $q } ) ) {
+		
+		if(length($q->param('process')) > 0) { 
+		
+			if($prof_sess->check_csrf($q) == 0){
+				$prof_sess->logout;
+				$q->param('flavor', 'profile_login');
+				return $self->profile_login();
+			}
+		}
+		
+        my $prof_data = $prof_sess->get( { -cgi_obj => $q } );
 
         require DADA::Profile::Fields;
         require DADA::Profile;
 
-        my $prof = DADA::Profile->new( { -email => $email } );
-        my $dpf = DADA::Profile::Fields->new( { -email => $email } );
+        my $prof = DADA::Profile->new( { -email => $prof_data->{email} } );
+        my $dpf = DADA::Profile::Fields->new( { -email => $prof_data->{email} } );
         my $subscriber_fields =
           $dpf->{manager}->fields( { -show_hidden_fields => 0, } );
         my $field_attr   = $dpf->{manager}->get_all_field_attributes;
         my $email_fields = $dpf->get;
 
@@ -15612,11 +15632,11 @@ sub profile {
 
             require DADA::Profile::Settings;
             my $dps = DADA::Profile::Settings->new({-list => $list});
             my $r   = $dps->save(
                 {
-                    -email   => $email,
+                    -email   => $prof_data->{email},
                     -setting => 'delivery_prefs',
                     -value   => $delivery_prefs,
                 }
             );
             $self->header_type('redirect');
@@ -15680,11 +15700,11 @@ sub profile {
 
                 require DADA::App::Subscriptions::Unsub;
                 my $dasu = DADA::App::Subscriptions::Unsub->new(
                     { -list => $i->{list} } );
                 my $unsub_link = $dasu->unsub_link(
-                    { -email => $email, -mid => '00000000000000' } );
+                    { -email => $prof_data->{email}, -mid => '00000000000000' } );
 
                 my $digest_timeframe =
                   formatted_runtime( $ls->param('digest_schedule') );
 
                 require DADA::Profile::Settings;
@@ -15693,11 +15713,11 @@ sub profile {
 						-list => $i->{list}
 					}
 				);
                 my $s   = $dps->fetch(
                     {
-                        -email => $email,
+                        -email => $prof_data->{email},
                     }
                 );
                 my $delivery_prefs = $s->{delivery_prefs} || 'individual';
                 push(
                     @$filled,
@@ -15720,11 +15740,12 @@ sub profile {
                     -with   => 'list',
                     -expr   => 1,
                     -vars   => {
                         errors => scalar $q->param('errors')
                           || 0,
-                        'profile.email'   => $email,
+                        'profile.email'   => $prof_data->{email},
+						csrf_token        => $prof_data->{token},
                         subscriber_fields => $fields,
                         subscriptions     => $filled,
                         has_subscriptions => $has_subscriptions,
                         welcome           => scalar $q->param('welcome')
                           || '',
@@ -15747,11 +15768,11 @@ sub profile {
 
                         gravators_enabled =>
                           $DADA::Config::PROFILE_OPTIONS->{gravatar_options}
                           ->{enable_gravators},
                         gravatar_img_url =>
-                          gravatar_img_url( { -email => $email, } ),
+                          gravatar_img_url( { -email => $prof_data->{email}, } ),
                         protected_directories => $protected_directories,
                         WHOLE_URL             => $whole_url,
                         %{ DADA::Profile::feature_enabled() },
 
                     }
@@ -16012,12 +16033,14 @@ sub profile_update_email {
             undef $prof_sess;
 
             my $prof_sess = DADA::Profile::Session->new;
             my $cookie    = $prof_sess->login(
                 {
-                    -email   => $profile_info->{'profile.update_email'},
-                    -no_pass => 1,
+                    -email           => $profile_info->{'profile.update_email'},
+                    -no_pass         => 1,
+                	-skip_validation => 1, 
+					
                 }
             );
 
             my $headers = {
                 -cookie  => [$cookie],
diff --git a/dada/DADA/Profile/Session.pm b/dada/DADA/Profile/Session.pm
index 7e6d3408..3d491887 100644
--- a/dada/DADA/Profile/Session.pm
+++ b/dada/DADA/Profile/Session.pm
@@ -88,30 +88,33 @@ sub _login_cookie {
 
     my $cookie;
 
     require CGI::Session;
 
+	use DADA::Security::Password; 
+
+	my $token = DADA::Security::Password::generate_rand_string(undef, 41); 
+
     my $session = new CGI::Session( $self->{dsn}, $q, $self->{dsn_args} );
 
-    $session->param( 'email',      cased($args->{ -email }) );
-    $session->param( '_logged_in', 1 );
+       $session->param( 'email',      cased($args->{ -email }) );
+       $session->param( '_logged_in', 1 );
+       $session->param( 'token',      $token);
+	
 
-    $session->expire( $DADA::Config::COOKIE_PARAMS{ -expires } );
-    $session->expire( '_logged_in', $DADA::Config::COOKIE_PARAMS{ -expires } );
+	    $session->expire( $DADA::Config::COOKIE_PARAMS{ -expires } );
+	    $session->expire( '_logged_in', $DADA::Config::COOKIE_PARAMS{ -expires } );
+	    $session->expire( 'token', $DADA::Config::COOKIE_PARAMS{ -expires } );
 
     $cookie = $q->cookie( 
 		%{$DADA::Config::PROFILE_OPTIONS->{cookie_params}},
 		-value => $session->id, 
 		($DADA::Config::PROGRAM_URL =~ m/^https/) ? (
 			-secure  => 1,
 		) : ()
 		
 		);
-
-    # My proposal to address the situation is quit relying on flush() happen
-    # automatically, and recommend that people use an explicit flush()
-    # instead, which works reliably for everyone.
     $session->flush();
 
     return $cookie;
 }
 
@@ -122,11 +125,20 @@ sub login {
     my ($args) = @_;
 
 	require CGI; 
 	my $q = new CGI; 
 
-    my ( $status, $errors ) = $self->validate_profile_login($args);
+	my ($status, $errors);
+	
+	if($args->{-skip_validation} == 0){ 
+	    ( $status, $errors ) = $self->validate_profile_login($args);
+	}
+	else { 
+		$status = 1; 
+		$errors = {};
+	}
+	
     if ( $status == 0 ) {
         croak "login failed.";
     }
     else {
         my $cookie = $self->_login_cookie($args);
@@ -180,10 +192,24 @@ sub validate_profile_login {
     my $errors = {
         unknown_user   => 0,
         incorrect_pass => 0,
     };
 
+
+    require DADA::Security::SimpleAuthStringState;
+    my $sast       = DADA::Security::SimpleAuthStringState->new;
+    my $auth_state = $args->{-auth_state};
+
+    if ( $DADA::Config::DISABLE_OUTSIDE_LOGINS == 1 ) {
+        if ( $sast->check_state($auth_state) != 1 ) {
+	        $status = 0;
+	        $errors->{invalid_form} = 1;
+        }
+
+    }
+
+
     require DADA::Profile;
     my $prof = DADA::Profile->new(
 		{ 
 			-email => $args->{ -email } 
 		} 
@@ -215,10 +241,34 @@ sub validate_profile_login {
 
     return ( $status, $errors );
 
 }
 
+sub check_csrf { 
+	my $self = shift; 
+	my $q    = shift; 
+	
+    my $s = CGI::Session->load( $self->{dsn}, $q, $self->{dsn_args} )
+      or croak 'failed to load session: ' . CGI::Session->errstr();
+	
+      if ( $s->is_expired ) {
+          return 0;
+      }
+
+      if ( $s->is_empty ) {
+          return 0;
+      }
+	
+	  if($q->param('csrf_token') eq $s->param('token') ){ 
+		  return 1; 
+	  }
+	  else { 
+		  return 0; 
+	  }
+	
+
+}
 sub is_logged_in {
 
     my $self = shift;
     my ($args) = @_;
     my $q;
@@ -228,10 +278,12 @@ sub is_logged_in {
     else {
         require CGI;
         $q = new CGI;
 
     }
+	
+	
     my $s = CGI::Session->load( $self->{dsn}, $q, $self->{dsn_args} )
       or croak 'failed to load session: ' . CGI::Session->errstr();
 
     if ( $s->is_expired ) {
         return 0;
@@ -270,11 +322,14 @@ sub get {
     require CGI;
     $q = new CGI;
     require CGI::Session;
 
     my $session = new CGI::Session( $self->{dsn}, $q, $self->{dsn_args} );
-    return $session->param('email');
+    return {
+		email => $session->param('email'), 
+		token => $session->param('token'),
+	}; 
 
 }
 
 sub reset_password {} # ??? 
 
diff --git a/dada/DADA/Template/Widgets.pm b/dada/DADA/Template/Widgets.pm
index fd13b936..194f7cf6 100644
--- a/dada/DADA/Template/Widgets.pm
+++ b/dada/DADA/Template/Widgets.pm
@@ -1248,22 +1248,22 @@ sub profile_widget {
 		$prof_sess_obj = $args->{-prof_sess_obj};
 	}
 	
 	
     my $scr              = '';
-    my $email            = '';
+    my $prof_data        = {};
     my $is_logged_in     = 0;
     my $profiles_enabled = $DADA::Config::PROFILE_OPTIONS->{enabled};
     if (   $DADA::Config::PROFILE_OPTIONS->{enabled} != 1)
     {
         $profiles_enabled = 0;
     }
     else {
 		if(defined($prof_sess_obj)){ 
 			if ( $prof_sess_obj->is_logged_in( { -cgi_obj => $q } ) ) {
                 $is_logged_in = 1;
-                $email = $prof_sess_obj->get( { -cgi_obj => $q } );
+                $prof_data = $prof_sess_obj->get( { -cgi_obj => $q } );
 			}
 		}
 		else {
 	        require DADA::Profile;
 	        my $dp = DADA::Profile->new( { -from_session => 1 } );
@@ -1271,11 +1271,11 @@ sub profile_widget {
 	            require DADA::Profile::Session;
 	            require CGI;
 	            my $prof_sess = DADA::Profile::Session->new;
 	            if ( $prof_sess->is_logged_in( { -cgi_obj => $q } ) ) {
 	                $is_logged_in = 1;
-	                $email = $prof_sess->get( { -cgi_obj => $q } );
+					$prof_data = $prof_sess->get( { -cgi_obj => $q } );
 	            }
 	        }
 		}
     }
 
@@ -1283,15 +1283,15 @@ sub profile_widget {
         {
             -screen => 'profile_widget.tmpl',
             -vars   => {
                 profiles_enabled  => $profiles_enabled,
                 is_logged_in      => $is_logged_in,
-                'profile.email'   => $email,
+                'profile.email'   => $prof_data->{email},
                 gravators_enabled => $DADA::Config::PROFILE_OPTIONS->{gravatar_options}->{enable_gravators},
                 gravatar_img_url => gravatar_img_url(
                     {
-                        -email                => $email,
+                        -email                => $prof_data->{email},
                         -size => 45,
                     }
                 ),
 
             }
diff --git a/dada/templates/profile_home.tmpl b/dada/templates/profile_home.tmpl
index aabe56d8..42d1b5a3 100644
--- a/dada/templates/profile_home.tmpl
+++ b/dada/templates/profile_home.tmpl
@@ -252,14 +252,15 @@
 <!-- tmpl_if list_settings.digest_enable -->
     <fieldset>
         <legend>Delivery Preferences:</legend>
         <form action="<!-- tmpl_var S_PROGRAM_URL -->" method="post"> 
 
-            <input type="hidden" name="flavor"        value="profile" > 
-            <input type="hidden" name="process"  value="profile_delivery_preferences" > 
-            <input type="hidden" name="list"     value="<!-- tmpl_var list_settings.list -->" > 
-
+            <input type="hidden" name="flavor"     value="profile" > 
+            <input type="hidden" name="process"    value="profile_delivery_preferences" > 
+            <input type="hidden" name="list"       value="<!-- tmpl_var list_settings.list -->" > 
+			<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
+			
 			<div class="row">
 				<div class="small-10 medium-5 large-4 columns">	 
 					
 					<div class="row">
 						<div class="small-12 columns">
@@ -344,12 +345,14 @@
 						</a>
 						<div id="profile_fields" class="content">
 							<div class="content-box section-box">
 
 				                <form action="<!-- tmpl_var PROGRAM_URL -->" method="post" accept-charset="<!-- tmpl_var HTML_CHARSET -->" id="membership_profile_fields"> 
-				                    <input type="hidden" name="flavor"        value="profile" > 
+				                    <input type="hidden" name="flavor"   value="profile" > 
 				                    <input type="hidden" name="process"  value="edit_subscriber_fields" > 
+									<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
+									
 				                    <!-- tmpl_loop subscriber_fields --> 
 
 										<div class="row">
 											<div class="large-3 medium-3 columns">
 												<label 
@@ -423,10 +426,12 @@
 				                will be replaced with this new email address, where it's allowed: 
 							</div>
 				            <form action="<!-- tmpl_var PROGRAM_URL -->" method="post" accept-charset="<!-- tmpl_var HTML_CHARSET -->"> 
 				                <input type="hidden" name="flavor"        value="profile" > 
 				                <input type="hidden" name="process"  value="update_email" >
+								<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
+								
 			                    <!-- tmpl_if errors_update_email --> 
 			                        <!-- tmpl_if error_invalid_email --> 
 			                            <p class="error"> 
 			                                * The email address you submitted is not valid.
 			                            </p> 
@@ -469,10 +474,11 @@
 						<div class="content-box section-box">
 							
 							<form action="<!-- tmpl_var PROGRAM_URL -->" method="post" accept-charset="<!-- tmpl_var HTML_CHARSET -->"> 
 				                <input type="hidden" name="flavor"        value="profile" > 
 				                <input type="hidden" name="process"  value="change_password" >
+								<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
 
 				                <!-- tmpl_if errors_change_password --> 
 				                        <p class="error">
 				                            Make sure that you re-typed your password correctly. 
 				                        </p>
@@ -511,10 +517,11 @@
 					<div id="delete_profile" class="content">
 						<div class="content-box section-box">
 				            <form action="<!-- tmpl_var PROGRAM_URL -->" method="post" accept-charset="<!-- tmpl_var HTML_CHARSET -->"> 
 				                <input type="hidden" name="flavor"        value="profile" > 
 				                <input type="hidden" name="process"  value="delete_profile" >
+								<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
         
 								<div class="alert-box info radius">
 							        Deleting your profile will remove all your profile information, but 
 				                    all your subscriptions to subscribed mailing lists will remain.
 								</div> 
diff --git a/dada/templates/profile_login.tmpl b/dada/templates/profile_login.tmpl
index 94691005..7a299213 100644
--- a/dada/templates/profile_login.tmpl
+++ b/dada/templates/profile_login.tmpl
@@ -192,10 +192,19 @@
 						id="profile_login"
 					> 
 						<input type="hidden" name="flavor" value="profile_login" > 
 						<input type="hidden" name="process" value="1" > 
 						
+						<!-- tmpl_if DISABLE_OUTSIDE_LOGINS --> 
+							<input 
+								type="hidden" 
+								name="auth_state" 
+								value="<!-- tmpl_var auth_state -->"
+							> 
+						<!--/tmpl_if--> 
+						
+						
 						<div class="row">
 							<div class="small-12 columns">
 								<label for="login_email">
 									Email Address
 								</label>

Vulnerable code:     if (   $DADA::Config::PROFILE_OPTIONS->{enabled} != 1) {

    if ( $DADA::Config::PROFILE_OPTIONS->{enabled} != 1 ) {
        return $self->default();
    }

            my $scrn              = '';
                -email    => xss_filter( scalar $q->param('login_email') ),
                -password => xss_filter( scalar $q->param('login_password') ),
                    -email => xss_filter( scalar $q->param('login_email') ),
                    -password =>
                      xss_filter( scalar $q->param('login_password') ),
                },
    if ( $prof_sess->is_logged_in( { -cgi_obj => $q } ) ) {
        my $email = $prof_sess->get( { -cgi_obj => $q } );
        my $prof = DADA::Profile->new( { -email => $email } );
        my $dpf = DADA::Profile::Fields->new( { -email => $email } );
                    -email   => $email,
                    { -email => $email, -mid => '00000000000000' } );
                        -email => $email,
                        'profile.email'   => $email,
                          gravatar_img_url( { -email => $email, } ),
                    -email   => $profile_info->{'profile.update_email'},
                    -no_pass => 1,
    $session->param( 'email',      cased($args->{ -email }) );
    $session->param( '_logged_in', 1 );
    $session->expire( $DADA::Config::COOKIE_PARAMS{ -expires } );
    $session->expire( '_logged_in', $DADA::Config::COOKIE_PARAMS{ -expires } );

    # My proposal to address the situation is quit relying on flush() happen
    # automatically, and recommend that people use an explicit flush()
    # instead, which works reliably for everyone.
    my ( $status, $errors ) = $self->validate_profile_login($args);
    return $session->param('email');
    my $email            = '';
                $email = $prof_sess_obj->get( { -cgi_obj => $q } );
	                $email = $prof_sess->get( { -cgi_obj => $q } );
                'profile.email'   => $email,
                        -email                => $email,
            <input type="hidden" name="flavor"        value="profile" > 
            <input type="hidden" name="process"  value="profile_delivery_preferences" > 
            <input type="hidden" name="list"     value="<!-- tmpl_var list_settings.list -->" > 

				                    <input type="hidden" name="flavor"        value="profile" > 
Fixed code:     if ( $DADA::Config::PROFILE_OPTIONS->{enabled} != 1) {
	
			my $scrn              = '';
			my $auth_state;
		    if ( $DADA::Config::DISABLE_OUTSIDE_LOGINS == 1 ) {
		        require DADA::Security::SimpleAuthStringState;
		        my $sast = DADA::Security::SimpleAuthStringState->new;
		        $auth_state = $sast->make_state;
		    }

		                auth_state      => $auth_state,
						
						
                -email      => xss_filter( scalar $q->param('login_email') ),
                -password   => xss_filter( scalar $q->param('login_password') ),
				-auth_state => xss_filter( scalar $q->param('auth_state') ),
                    -email           => xss_filter( scalar $q->param('login_email') ),
                    -password        => xss_filter( scalar $q->param('login_password') ),					
                	-skip_validation => 1, 
				},
	
	
	
    if ($prof_sess->is_logged_in( { -cgi_obj => $q } ) ) {
		
		if(length($q->param('process')) > 0) { 
		
			if($prof_sess->check_csrf($q) == 0){
				$prof_sess->logout;
				$q->param('flavor', 'profile_login');
				return $self->profile_login();
			}
		}
		
        my $prof_data = $prof_sess->get( { -cgi_obj => $q } );
        my $prof = DADA::Profile->new( { -email => $prof_data->{email} } );
        my $dpf = DADA::Profile::Fields->new( { -email => $prof_data->{email} } );
                    -email   => $prof_data->{email},
                    { -email => $prof_data->{email}, -mid => '00000000000000' } );
                        -email => $prof_data->{email},
                        'profile.email'   => $prof_data->{email},
						csrf_token        => $prof_data->{token},
                          gravatar_img_url( { -email => $prof_data->{email}, } ),
                    -email           => $profile_info->{'profile.update_email'},
                    -no_pass         => 1,
                	-skip_validation => 1, 
					
	use DADA::Security::Password; 

	my $token = DADA::Security::Password::generate_rand_string(undef, 41); 

       $session->param( 'email',      cased($args->{ -email }) );
       $session->param( '_logged_in', 1 );
       $session->param( 'token',      $token);
	
	    $session->expire( $DADA::Config::COOKIE_PARAMS{ -expires } );
	    $session->expire( '_logged_in', $DADA::Config::COOKIE_PARAMS{ -expires } );
	    $session->expire( 'token', $DADA::Config::COOKIE_PARAMS{ -expires } );
	my ($status, $errors);
	
	if($args->{-skip_validation} == 0){ 
	    ( $status, $errors ) = $self->validate_profile_login($args);
	}
	else { 
		$status = 1; 
		$errors = {};
	}
	

    require DADA::Security::SimpleAuthStringState;
    my $sast       = DADA::Security::SimpleAuthStringState->new;
    my $auth_state = $args->{-auth_state};

    if ( $DADA::Config::DISABLE_OUTSIDE_LOGINS == 1 ) {
        if ( $sast->check_state($auth_state) != 1 ) {
	        $status = 0;
	        $errors->{invalid_form} = 1;
        }

    }


sub check_csrf { 
	my $self = shift; 
	my $q    = shift; 
	
    my $s = CGI::Session->load( $self->{dsn}, $q, $self->{dsn_args} )
      or croak 'failed to load session: ' . CGI::Session->errstr();
	
      if ( $s->is_expired ) {
          return 0;
      }

      if ( $s->is_empty ) {
          return 0;
      }
	
	  if($q->param('csrf_token') eq $s->param('token') ){ 
		  return 1; 
	  }
	  else { 
		  return 0; 
	  }
	

}
	
	
    return {
		email => $session->param('email'), 
		token => $session->param('token'),
	}; 
    my $prof_data        = {};
                $prof_data = $prof_sess_obj->get( { -cgi_obj => $q } );
					$prof_data = $prof_sess->get( { -cgi_obj => $q } );
                'profile.email'   => $prof_data->{email},
                        -email                => $prof_data->{email},
            <input type="hidden" name="flavor"     value="profile" > 
            <input type="hidden" name="process"    value="profile_delivery_preferences" > 
            <input type="hidden" name="list"       value="<!-- tmpl_var list_settings.list -->" > 
			<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
			
				                    <input type="hidden" name="flavor"   value="profile" > 
									<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
									
								<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
								
								<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
								<input type="hidden" name="csrf_token" value="<!-- tmpl_var csrf_token -->">
						<!-- tmpl_if DISABLE_OUTSIDE_LOGINS --> 
							<input 
								type="hidden" 
								name="auth_state" 
								value="<!-- tmpl_var auth_state -->"
							> 
						<!--/tmpl_if-->