SonarQube Marks Echo Statements as XSS Despite Middleware Sanitization

Hi Community,

I’m encountering a persistent XSS detection issue with SonarQube in a PHP project, even though I’m using middleware for sanitization.

Here’s a sample of the code I’m working with to reproduce the issue:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Result Page</title>
</head>
<body>
<?php 
require "classes/sanitize.php";
$sanitizer = new SanitizeMiddleware();
$sanitizer->handle();

echo "Username: " .$_POST['username'] ."</p>";
?>
    <h2>Result Page</h2>
    <p>Username: <?php echo $_POST['username']; ?></p>
    <p>Email: <?php echo $_POST['email']; ?></p>
    <p>Comment: <?php echo $_POST['comment']; ?></p>
    <a href="form.php">Back to Form</a>
</body>
</html>

My middleware:

<?php
class SanitizeMiddleware {
    public function handle() {
        // Apply htmlspecialchars to each POST variable
        foreach ($_POST as $key => $value) {
            $_POST[$key] = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
        }
    }
}

I’m using a custom SanitizeMiddleware to handle input sanitization for XSS prevention without modifying each echo statement individually. However, SonarQube consistently flags these echo and <?php echo ?> statements as potential XSS vulnerabilities.

Environment Details:

  • SonarScanner CLI: 6.2.1.4610
  • Java Version: 17.0.12 (Eclipse Adoptium 64-bit)
  • OS: Linux 6.8.11-amd64
  • SonarQube Server Version: 10.2.0.77647

Is there a way to configure SonarQube to recognize the middleware-based sanitization, or is this an inherent limitation of the current scanning setup?

Any advice or guidance on handling this scenario would be greatly appreciated. Thank you!

Roman

Hi Roman,

Welcome to the community!

What edition are you using? Enterprise Edition($$) offers taint analysis configuration.

 
Ann

Hello Ann,
I’m using the Enterprise edition.

Hi,

Then the docs I linked to above should help.

 
Ann

Hello Ann,

After spending all evening and this morning trying, I couldn’t figure out how to create a “PHP custom configuration” rule for the PoC I provided.

Hi,

Can you show your work? We should be able to go from there.

 
Ann

Here is the code I’ve tried

{
  "S5131": {
    "sources": [
      {
        "methodId": "_POST"
      }
    ],
    "sanitizers": [
      {
        "methodId": "SanitizeMiddleware::handle",
        "args": [0]
      }
    ],
    "sinks": [
      {
        "methodId": "echo",
        "isMethodPrefix": false,
        "args": [0]
      }
    ]
  }
}

Hi,

Thanks. I’ve flagged this for more expert eyes.

 
Ann

Hi @Roman_Kis,

Unfortunately, this is a limitation of our engine. It is not able to infer that:

$_POST[$key] = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');

will sanitize (for example) $_POST['username']. We do not make the link between $_POST[$key] in a loop and $_POST['username'].

So even if you use a custom configuration like you do, we will still raise a false positive. we currently do not have a way to circumvent this limitation.

Hello Sebastien,

Thank you for your explanation. I’d like to delve a bit further into the issue, if you don’t mind.

Following your logic, I could technically create an (admittedly clunky) function to sanitize inputs like this:

<?php
class SanitizeMiddleware {
    public function handle() {
        $_POST["username"] = htmlspecialchars($_POST["username"], ENT_QUOTES, 'UTF-8');
        // A row for each parameter
    }
}

I’ve tried this approach, and even though the “username” is properly sanitized, it still gets flagged as XSS.

Essentially, I can’t label 3700 XSS findings as false positives across our large project, nor can I produce a report with 3700 flagged XSS issues for our customers.

Is there any way for me to implement a new kind of middleware to fix this in a reasonable amount of time?

Thank you,

Roman

Sure.

Sanitizers need a parameter (the value that will be sanitized). Your handle does not have one, so it is not considered as a sanitizer for $_POST["username"]. If instead you use the code:

<?php 
class SanitizeMiddleware {
    public function sanitize($var) {
        return htmlspecialchars($var, ENT_QUOTES, 'UTF-8');
    }
}

...

$sanitizer = new SanitizeMiddleware();
$_POST['username'] = $sanitizer->sanitize($_POST['username']);
$_POST['email'] = $sanitizer->sanitize($_POST['email']);
?>
<p>Username: <?php echo $_GET['username']; ?></p>
<p>Email: <?php echo $_GET['email']; ?></p>
...

it will not raise. However, it is quite useless.

I do not see any way to write a middleware that would circumvent the limitation of our engine.

Regards
Sebastien