
\begin{enumerate}[label={V2.\arabic*}]

\item
\fail{}
Verify all pages and resources by default require
authentication except those specifically intended to be
public (Principle of complete mediation).

\begin{result}
    All admin pages are private. Unpublished posts are also private.
    However, the install submission page does not do any authentication at all,
    allowing any user to reset the database and claim an admin account.
    User pages can be viewed (and submitted) by any authenticated user.
\end{result}

\item
\pass{}
Verify that forms containing credentials are not filled in by
the application. Pre-filling by the application implies that
credentials are stored in plaintext or a reversible format,
which is explicitly prohibited.

\begin{result}
No credentials (that should not be stored in plain text) are ever filled in by
the application.
\end{result}

\setcounter{enumi}{3}

\item
\pass{}
Verify all authentication controls are enforced on the
server side.

\begin{result}
    All authentication controls (login credentials and client cookies) are
    enforced by the application. Note however item~\ref{auth:6}, about the
    security of these controls in the immplementation.
\end{result}

\setcounter{enumi}{5}

\item\label{auth:6}
\fail{}
Verify all authentication controls fail securely to ensure
attackers cannot log in.

\begin{result}
    The input to various forms is not sanitized at all. This makes the implementation
    in (not only) \code{Users::find} vulnerable to \SQL{} injections. The login form
    is also vulnerable. Any user can execute arbitrary \SQL{} code from the username field.
    The following example code can submitted as username in the login form, which
    will set the password of the \code{admin} user to \code{s3cret}:

    \code{"; UPDATE users SET password='\$1\$OWgsBb90\$Lkko6aZwmp9XOVrFI09Ab0' WHERE \\username='admin' AND 'a' = "a}

    After using this exploit, the attacker (of course) knows the admin password.
\end{result}

\item
\pass{}
Verify password entry fields allow, or encourage, the use
of passphrases, and do not prevent password managers,
long passphrases or highly complex passwords being
entered.

\begin{result}
    The application allows the user to use any password (except ones that contain
	\SQL{} code).
\end{result}

\item
\pass{}
Verify all account identity authentication functions (such
as update profile, forgot password, disabled / lost token,
help desk or IVR) that might regain access to the account
are at least as resistant to attack as the primary
authentication mechanism.

\begin{result}
    The only alternative mechanism for authenticating (except for using
    vulnerabilities as described in other point) is using the ``Recover
    password'' functionality. This sends a secret token to the email
    address owning the account.

    After such a token is used, it cannot be reused, because the token is
    derived from the password hash (and thus a random salt). Tokens do not
    expire, however. It would be even better to require that a token be used
    withing a day (or so) after creation.

	The security of the \SMTP{} connection is at the discretion of the web server.
    Often these connections are not very secure, but this worry is beyond the
    scope of this audit.
\end{result}

\item
\fail{}
Verify that the changing password functionality includes
the old password, the new password, and a password
confirmation.

\begin{result}
    Changing a user's password does not require the original password, nor does the
    password Changing form request for a password confirmation. This makes it easy
    to set a wrong password for yourself.
\end{result}

\setcounter{enumi}{11}

\item
\fail{}
Verify that all authentication decisions can be logged,
without storing sensitive session identifiers or passwords.
This should include requests with relevant metadata
needed for security investigations.

\begin{result}
    The application does not log any notable authentication event.
\end{result}

\item
\fail{}
Verify that account passwords are one way hashed with a
salt, and there is sufficient work factor to defeat brute
force and password hash recovery attacks.

\begin{result}
	Password are stored in database using the \PHP{} function \code{crypt}. Internally, this
    function uses salted MD5. This is way too reverse with brute-force attacks using dictionary files.

    Instead it would be better to use the \code{argon2} password hashing algorithm
	or the \PHP{} \code{password\_hash} function (which currently uses BCRYPT).
\end{result}

\setcounter{enumi}{15}

\item
\fail{}
Verify that credentials are transported using a suitable
encrypted link and that all pages/functions that require a
user to enter credentials are done so using an encrypted
link.

\begin{result}
	The app allows admin users to log in over \HTTP{}. This is insecure, as it allows
    eavesdroppers to intercept password.
	The app should force \HTTPS{} for at least the login form, the \code{admin\_controller} and
    for the installation script (because the users posts secrets like the database
    password to this page).
\end{result}

\item
\pass{}
Verify that the forgotten password function and other
recovery paths do not reveal the current password and
that the new password is not sent in clear text to the user.

\begin{result}
    No password is stored in plain text. The password recovery path works with
    a secret token, which is used to reset the password. Although this token
    is derived from the password hash, it does not reveal any secret
    information.
\end{result}

\item
\fail{}
Verify that information enumeration is not possible via
login, password reset, or forgot account functionality.

\begin{result}
    All these forms are vulnerable to \SQL{} injection attacks. So any information
    can leak any information from the database.
\end{result}

\item
\pass{}
Verify there are no default passwords in use for the
application framework or any components used by the
application (such as “admin/password”).

\begin{result}
    No secrets are initialized by predefined values. The admin user will have
    username \code{admin} by default. This is no secret and therefore not
    considered unsafe.
\end{result}

\item
\fail{}
Verify that anti-automation is in place to prevent breached
credential testing, brute forcing, and account lockout
attacks.

\begin{result}
    No anti-automation measures are deployed.

    This is needed for:
    \begin{itemize}
        \item Email validation, to harden brute force email address discovery
        \item Installation database check, to prevent guessing attacks for the database password
        \item Login, to prevent login guessing
        \item And comment submission, to prevent spam, phishing et cetera (by
        using some CAPTCHA software).
    \end{itemize}
\end{result}

\item
\fail{}
Verify that all authentication credentials for accessing
services external to the application are encrypted and
stored in a protected location.

\begin{result}
    The database credentials are hardcoded in \code{config.php}. While it
    would be better to pass secrets as environment variables, this is not
    really bad practice.

    However, the installation instructions state the following:
    \begin{verbatim}
Change the file permissions to allow all users write access to the folder
you extracted testcms to.
    \end{verbatim}
    This implies making the configuration file readable for all users on the
    system. This information should not be accessible for any user other than
	running the \PHP{} script.
\end{result}

\item
\pass{}
Verify that forgotten password and other recovery paths
use a \TOTP{} or other soft token, mobile push, or other
offline recovery mechanism. Use of a random value in an
e-mail or SMS should be a last resort and is known weak.

\begin{result}
    The password recovery path uses a random looking token. It is sent over
    e-mail, which is considered weak (but not unsafe).
\end{result}

\notapplicable{\item
Verify that account lockout is divided into soft and hard
lock status, and these are not mutually exclusive. If an
account is temporarily soft locked out due to a brute force
attack, this should not reset the hard lock status.

%     The application has not implemented any lockout mechanisms.
}

\notapplicable{\item
Verify that if shared knowledge based questions (also
known as ``secret questions'') are required, the questions
do not violate privacy laws and are sufficiently strong to
protect accounts from malicious recovery.}

\item
\fail{}
Verify that the system can be configured to disallow the
use of a configurable number of previous passwords.

\begin{result}
    The system does not remember any previously used passwords and does not
    require variation in the use of different passwords.
\end{result}

\notapplicable{\item
Verify that risk based re-authentication, two factor or
transaction signing is in place for high value transactions.}

% There are no (really) risk based action or which re-authentication would be
% fit

\item
\fail{}
Verify that measures are in place to block the use of
commonly chosen passwords and weak passphrases.

\begin{result}
    No password strengthening measures are implemented. The app should
    use some password strength estimator like \texttt{zxcvbn}\footnote{\url{https://github.com/dropbox/zxcvbn}}.
\end{result}

\item
\fail{}
Verify that all authentication challenges, whether
successful or failed, should respond in the same average
response time.

\begin{result}
    String comparisation for checking password hases and password reset tokens
    are not in constant time.
\end{result}

\item
\fail{}
Verify that secrets, \API{} keys, and passwords are not
included in the source code, or online source code
repositories.

\begin{result}
    The database credentials are hard coded in \code{config.php}. These
    credentials should ideally be passed using environment variables.
\end{result}

\setcounter{enumi}{30}

\notapplicable{\item
Verify that if an application allows users to authenticate,
they can authenticate using two-factor authentication or
other strong authentication, or any similar scheme that
provides protection against username + password
disclosure.}

\item
\fail{}
Verify that administrative interfaces are not accessible to
untrusted parties.

\begin{result}
    Any authenticated user is allowed to view and use the administrative
    interface. A separation should be made between administrators and normal
    users.
\end{result}

\item
\pass{}
Browser autocomplete, and integration with password
managers are permitted unless prohibited by risk based
policy.

\begin{result}
    Browser autocomplete functionality is not restricted in any way.
\end{result}

\end{enumerate}
