Privacy Patches for Webmail


anti-fixation plugin

A session fixation attack is when the attacker is able to ‘seed’ a particular session id in the user’s browser. The attacker can do this in a variety of ways, most of which require that they are able to post custom html on a similar domain to the squirrelmail login page. When the user views this custom html, their browser can be tricked into adopting a predetermined session id picked by the attacker.

Here is a trivial example of some fixating html:

<meta http-equiv="Set-Cookie" content="SQMSESSID=31d857c52046d2e418ea5f24675e5180;;path=/">

This tag can appear anywhere in the page, on any page, on any site with a domain of or a subdomain of If you have any website hosted at or which allows people to post html content, then the attacker could post this tag and gain access to squirrelmail running on

Once the user has adopted this predetermined session id (by viewing the html), if the user then logs into squirrelmail the attacker will be able to access their account. This is because the attacker has a cookie in their browser which exactly matches the cookie in the user’s browser. Squirrelmail will treat both the attacker and the user as the same client with the same valid session. With some browsers, the meta tag could even be within a correctly formatted url which was posted to the page. SSL does nothing to prevent this.

This plugin attempts to banish such attacks by ensuring that the session id is created anew each and every time there is a successful authentication. This has the added benefit of preventing a user from seeing the cached session data of
another user who forgot to logout while using the same computer (it can be confusing to send mail with the other user’s return address!).

And, as always, if you care anything about security, make sure that the sessions are only using cookies and not URL rewriting (ie session.use_only_cookies = 1).


Download plugin 1.0->]


To understand session fixation attacks, a good primer is:

Cross site cookie attacks. These attacks make it possible to do session fixation even from a non-similar domain.

Wikipedia Reading:


In order to prevent session fixation, we must make sure we delete all the possible session cookies which might exist and which would take priority over our new one. This turns out to be difficult: php will fall back to the session cookie with the shortest path and shortest domain name. Since an attacker would pick this type of cookie, we are forced into creating our session cookie with an equally global scope.

In theory, we should be able to delete all the possible cookies with a more global scope than the one we create. This way, we could use a cookie with a path consistant with the squirrelmail configuration.

Unfortunately, squirrelmail has a small bug: on the login page, there is a session cookie set with a root path irrespective of what the session path should be. Later code sets a path for the session cookie: this is all fine and well, but if a root path session cookie is created first, then these others are not used in practice.

this initial bad session is created from:

 login.php --> include(strings.php) -->
     include(global.php) --> sqsession_is_active();

This session is created before:
  $base_uri = sqm_baseuri()
  session_set_cookie_params(0, $base_uri)

This means that we are actually stuck using a root path session cookie, no matter what the code elsewhere seems to think. If we chose to follow squirrelmail and create session cookie with a path, the root path cookie would always take precidence on the next page refresh over our newly created session cookies.

PHP appears to adopt whatever path is set in an available session if you don’t explicitly call session_set_cookie_params before starting the session.

NOTES: We are no longer using this, as SM seems to have fixed the problem. Oddly this plugin was preventing login on Firefox since the upgrade to jessie (the SM code didn’t change, but the PHP version did.) This plugin was creating (only with firefox) extra cookies on the root path that prevented a user from logging in.
Here is the SM patch fixing fixation issues:

privacy patch

Squirrelmail puts the IP address of the user’s home computer in every email they send out. Some might consider this a horrible breach of privacy. This patch will prevent this, but still includes the login name of the authenticated user.


You can download squirrelmail-1.4.4-privacy.diff directly from our git repository. The code is pretty simple, so it is represented below (copying and pasting this will result in problems, better to download it).

*-- ./Deliver.class.php 2004-12-27 07:03:41.000000000 -0800
+++ /var/www/squirrelmail-1.4.4/class/deliver/Deliver.class.php 2005-02-06 15:13:24.000000000 -0800
bc. -380,7 +380,7 @@
         /* This creates an RFC 822 date */
         $date = date('D, j M Y H:i:s ', mktime()) . $this->timezone();
         /* Create a message-id */
+        $message_id = '<' . $REMOTE_PORT . '.' . $username . '.';
*        $message_id = '<' . $REMOTE_PORT . '.' . $REMOTE_ADDR . '.';
         $message_id .= time() . '.squirrel@' . $SERVER_NAME .'>';
         /* Make an RFC822 Received: line */
         if (isset($REMOTE_HOST)) {
bc. -394,7 +394,6 @@
             $received_from .= " (proxying for $HTTP_X_FORWARDED_FOR)";
+        $received_from = "localhost (";
         $header = array();
         $header[] = "Received: from $received_from" . $rn;
         $header[] = "        (SquirrelMail authenticated user $username)" . $rn;


This new Squirrelmail version has a so-called “encode_header_key” feature, which actually provides quite poor encryption (especially since the padding string is always the same and stored in /etc/, if you really want to know you can get it there).

The following patch prevents any home IP address to appear in the headers, no matter which way you’ve set your “encode_header_key” option to.

You can download squirrelmail-1.4.6-privacy.diff directly from our git repository (this patch works for 1.4.6, 1.4.7 and 1.4.8 even though it is named 1.4.6). The code is pretty simple, so it is represented below (copying and pasting this will result in problems, better to download it).

*-- class/deliver/Deliver.class.php.orig        2006-02-07 13:01:24.000000000 -0800
+++ class/deliver/Deliver.class.php     2006-02-07 13:37:45.000000000 -0800
bc. -399,12 +399,7 @@
         $date = date('D, j M Y H:i:s ', mktime()) . $this->timezone();
         /* Create a message-id */
         $message_id = '<' . $REMOTE_PORT . '.';
*        if (isset($encode_header_key) && trim($encode_header_key)!='') {
*            // use encrypted form of remote address
*            $message_id.= OneTimePadEncrypt($this->ip2hex($REMOTE_ADDR),base64_encode($encode_header_key));
*        } else {
*            $message_id.= $REMOTE_ADDR;
*        }
+        $message_id .= $username ;
         $message_id .= '.' . time() . '.squirrel@' . $SERVER_NAME .'>';
         /* Make an RFC822 Received: line */
         if (isset($REMOTE_HOST)) {
bc. -418,6 +413,8 @@
             $received_from .= " (proxying for $HTTP_X_FORWARDED_FOR)";
+        $received_from = "localhost (";
+        $REMOTE_ADDR = "";
         $header = array();


The following patches are in our privacy git repository

--- squirrelmail-1.4.21/class/deliver/ 2010-06-25 14:31:10.000000000 -0700
+++ squirrelmail-1.4.21/class/deliver/squeeze_Deliver.class.php	2011-07-25 16:56:00.257529266 -0700
bc. -572,11 +572,12 @@
             $SERVER_NAME = $domain;
-        sqGetGlobalVar('REMOTE_ADDR', $REMOTE_ADDR, SQ_SERVER);
-        sqGetGlobalVar('REMOTE_PORT', $REMOTE_PORT, SQ_SERVER);
-        sqGetGlobalVar('REMOTE_HOST', $REMOTE_HOST, SQ_SERVER);
-        sqGetGlobalVar('HTTP_VIA',    $HTTP_VIA,    SQ_SERVER);
+        //sqGetGlobalVar('REMOTE_ADDR', $REMOTE_ADDR, SQ_SERVER);
+	$REMOTE_ADDR = "localhost (";
+        //sqGetGlobalVar('REMOTE_PORT', $REMOTE_PORT, SQ_SERVER);
+        //sqGetGlobalVar('REMOTE_HOST', $REMOTE_HOST, SQ_SERVER);
+        //sqGetGlobalVar('HTTP_VIA',    $HTTP_VIA,    SQ_SERVER);
         $rn = "\r\n";


For wheezy, I manually patched the wheezy file, patching the lines as done in 1.4.21

Horde (IMP) Privacy Patch

Horde does a couple things that compromise a user’s anonymity in the IMP webmail client in unnecessary ways:

1. Received: header added with user’s home DSL/cable IP. Horde does the same thing that Squirrelmail does. The following patch changes this so it says “localhost (localhost” again.

2. If a user clicks the help button and sends in a problem report, you get the http headers that their UA sends as well as their IP. The IP address is really unnecessary information for debugging problems.

3. Last login data is saved into the database and displayed to the user on login. The display of this data is controlled by a prefs.php setting, however even with this set to off, the data is still collected in the database! With these patches, the last_login will not be displayed at all, and the code that writes this information to the database has been commented out. As a minor speed-up bonus, the code that attempts to read this information from the database has also been commented out, no point in reading data that is always going to be the same!

You can download the latest horde privacy patch which works for Debian Squeeze (3.3.8), there are also older ones available too (horde-3.1-privacy.diff or the Debian Sarge version (Thanks to Nadir technik) horde3.0.4-4sarge3-privacy.diff). These are all available directly from our git repository. The code is pretty simple, but longer, so it has been omitted from this page, you can see it by clicking on either of the above links.

If you were running IMP before you might have a handful of data collected already in the database, you will want to anonymize these, you can do this by doing the following:

mysql> UPDATE horde_prefs set pref_value='a:2:{s:4:"time";i:1134251455;s:4:"host";s:30:"anonymized";}' where pref_name='last_login';