Invalid Security Token

Hello. Bit of strangeness happened to me yesterday. Running 3.6.6
Fired up phplist for the monthly newsletter, but when I tried to import new subscribers (via a csv file as I always do) I got the Invalid Security Token message. No matter what I do, reset the session, log out, empty the cache, I’m still getting the same error. I also get it when I try to export subscribers. Since I had not touched anything at all since last time it worked, I thought it was my ISP ( that finally lost it so I made a clean installation on another server with another ISP, copied the DB and… still getting the same error. So it seems to be carried over with the DB.

I spent a couple of days trying to make it worked and I looked through the forums for any signs of anyone with a similar problem but without luck. Does anyone have any idea?


@KhaledBey Check that the admintoken table exists in the database.

Hello! Yes indeed the admintoken table is present.

@KhaledBey Try an import, there should be a row added with your admin id and the time of loading the import page and a token. phplist checks the token when you submit the form.

ok this is weird. the entry in the DB with the corresponding timestamp is: 0480d867a61185749eddf45b52685703
But the value in the browser is:

@KhaledBey Can you try using the browser developer tools to track the network traffic when navigating through those pages. That might help to see what is happening.

OK I’m not very familiar with what exactly to look for, but the token that comes after
and phpList_ui_bootlist.min.js?v=

is not the same as the “initiator” at ?page=export&tk=

Is that a problem?

@KhaledBey You are looking at the wrong values.

In the html for the import page there is a formtoken hidden input field. When you load the first page the value in the page html should match a row in the admintoken table.
When you submit that page then the hidden field should be in the request data. If phplist is rejecting the submission then you need to see why the submitted value no longer exists in the table.

OK the hidden formtoken value in the html for the import page matches the latest row in the admintoken table. But when I submit the page, that value is nowhere to be seen in the network requests. Instead it submits another value that doesnt match anything in the admintoken table.

@KhaledBey This is what happens for me
In the html of the first import page

Screenshot from 2021-12-09 22-18-45

Then submitting that page with the same value

Screenshot from 2021-12-09 22-18-05

When the token matches then phplist deletes the row from the admintoken table.

I don’t really know what is happening in your case.

Hello again, and thank you very much for your help so far.
I can’t manage to get the exact same “request payload” screen in the dev tools of Chrome as you? But this is what I got:

Since the tokens don’t match up. The admintoken table in the DB fills up with rows that stays for what seems to be a little bit more than 2 hours.

I just tested a clean phplist install in an empty DB and the error does not persist, so it is somehow related to my old DB.

I found a workaround.
If I login to phplist
then in phpmyadmin drop the admintoken table
then recreate it with the initialise database function in phplist
the token matching works until I logout and in again in phplist.
then the error comes back and I have to reapply the workaround.

You are looking at the wrong field. That is a separate token in the URL, you need to look at the body of the request when you submit the import form for a field named “formtoken”.

When the form tokens do match then phplist deletes the row from the admintoken table, and also deletes all rows that have expired (more than one hour old).

What is your environment - web server and database server? Also, might be a time zone problem making it look like the token has expired, but not sure how.

You could try adding some debug to the function verifyToken() in file admin/lib.php

echo $_POST['formtoken'];
    //# @@@TODO for now ignore the error. This will cause a block on editing admins if the table doesn't exist.
    $req = Sql_Fetch_Row_Query(sprintf('select id from %s where adminid = %d and value = "%s" and expires > now()',
        $GLOBALS['tables']['admintoken'], $_SESSION['logindetails']['id'], sql_escape($_POST['formtoken'])), 1);