Dashboard site being flagged as unsafe by Google Safe Browsing

Without any change to our code, Google started flagging our dashboard site as “unsafe.”

I deployed the latest dashboard code and submitted for review. The review came back clear at first, but then almost immediately, it was flagged again.

Only the /dashboard/apps and /dashboard/login endpoints are flagged even though the same domain also hosts our parse server at /parse.

This is the message from Google’s Search Console:

Google has detected harmful content on some of your site’s pages. We recommend that you remove it as soon as possible. Until then, browsers such as Google Chrome will display a warning when users visit or download certain files from your site.

Deceptive pages

These pages attempt to trick users into doing something dangerous, such as installing unwanted software or revealing personal information. Learn more

Anyone ever gotten this for the dashboard before or have any idea what Google could be flagging specifically?

Could you share more details on how you are deploying your dashboard? It may also be another content you have in the same domain.

It is hosted on azure, so the domain is https://our-subdomain.azurewebsites.net.
The only thing on the same subdomain is parse server.

We are running as express middleware with parse server on the same url and port:

var express = require("express");
var ParseServer = require("parse-server").ParseServer;
var ParseDashboard = require("parse-dashboard");
var MyFirebaseAuthAdapter = require("./myFirebaseAuthAdapter");

var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;

if (!databaseUri) {
    console.log("DATABASE_URI not specified, falling back to localhost.");
}

var serverUrl = process.env.SERVER_URL || "http://localhost:1337/parse";

var serverConfig = {
    databaseURI: databaseUri || "mongodb://localhost:27017/dev",
    cloud: process.env.CLOUD_CODE_MAIN || __dirname + "/cloud/main.js",
    appId: process.env.APP_ID || "myAppId",
    masterKey: process.env.MASTER_KEY || "123",
    serverURL: serverUrl,

    appName: process.env.APP_NAME || "mysite.org",

    auth: { myauth: MyFirebaseAuthAdapter },

    allowClientClassCreation: false,
};
var api = new ParseServer(serverConfig);
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey

var dashboard = new ParseDashboard({
    apps: [
        {
            appId: serverConfig.appId,
            serverURL: serverConfig.serverURL,
            masterKey: serverConfig.masterKey,
            appName: serverConfig.appName,
            production: serverConfig.serverURL.includes("production"),
        },
    ],
    trustProxy: 1,
    users: [
        {
            user: serverConfig.appId,
            pass: serverConfig.masterKey,
        },
    ],
});

var app = express();

// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || "/parse";
app.use(mountPath, api);

app.use("/dashboard", dashboard);

var port = process.env.PORT || 1337;
var httpServer = require("http").createServer(app);
httpServer.listen(port, function () {
    console.log("parse-server running on port " + port + ".");
});

Note that since Google flagged it, we have since turned on the setting in Azure to force https. We also correctly configured the trustProxy setting. So it is possible it was related to one of those, but it still seems like the Google bot must have seen something in code, not just the configuration.

I think it is most likely something regarding https.

Alas, after forcing https, this is still a problem.

After resolving all the potential issues with https, I submitted for review.
After a couple days, Google determined the site was clean:

Google has received and processed your security review request. Google systems indicate that https://our-subdomain.azurewebsites.net/ no longer contains links to harmful sites or downloads. The warnings visible to users are being removed from your site.

But 5 days later, without any change to the site, Google flagged the site again.
The message on the Search Console is the same as in my original post above.
Here is the relevant text of the notification email:

Social engineering content detected on https://our-subdomain.azurewebsites.net/

Google’s Safe Browsing systems have detected that some pages on your site might be hacked or might include third party resources such as ads that are designed to trick users into installing malicious software or giving up sensitive information. To protect your site’s visitors, affected pages have been demoted in Google’s search results, and browsers such as Google Chrome now display a warning when users visit your site. You can see which pages might be affected in the Security Issues report.

Again, it was the /dashboard/apps and /dashboard/login endpoints which were flagged.

I let sitecheck.sucuri.net evaluate the site, and it gave me a clue which led me to look at the html being generated for the login page:

<!DOCTYPE html>
        <head>
          <link rel="shortcut icon" type="image/x-icon" href="/dashboard/favicon.ico" />
          <base href="/dashboard/"/>
          <script>
            PARSE_DASHBOARD_PATH = "/dashboard/";
          </script>
        </head>
        <html>
          <title>Parse Dashboard</title>
          <body>
            <div id="login_mount"></div>
            
            <script id="csrf" type="application/json">"jyAMQr0Q-45qwGvtwXZjvVJJvMI1Q7WLT1ng"</script>
            <script src="/dashboard/bundles/login.bundle.js"></script>
          </body>
        </html>

Notice the two opening <html> tags.
I think this is what Google is flagging since it then sees the first <script> tag as outside the <html> tags.

Github history shows this invalid html has been in parse-dashboard/Parse-Dashboard/app.js for at least six years.

I created an issue and PR:

Does the issue still occur after the PR has been merged?