Security Analysis in Psalm

Psalm can attempt to find connections between user-controlled input (like $_GET['name']) and places that we don’t want unescaped user-controlled input to end up (like echo "<h1>$name</h1>" by looking at the ways that data flows through your application (via assignments, function/method calls and array/property access).

You can enable this mode with the --taint-analysis command line flag. When taint analysis is enabled, no other analysis is performed.

Tainted input is anything that can be controlled, wholly or in part, by a user of your application. In taint analysis, tainted input is called a taint source.

Example sources:

  • $_GET[‘id’]
  • $_POST['email']
  • $_COOKIE['token']

Taint analysis tracks how data flows from taint sources into taint sinks. Taint sinks are places you really don’t want untrusted data to end up.

Example sinks:

  • <div id="section_<?= $id ?>">
  • $pdo->exec("select * from users where name='" . $name . "'")

Taint Types

Psalm recognises a number of taint types by default, defined in the Psalm\Type\TaintKind class:

  • sql - used for strings that could contain SQL
  • ldap - used for strings that could contain a ldap DN or filter
  • html - used for strings that could contain angle brackets or unquoted strings
  • shell - used for strings that could contain shell commands
  • callable - used for callable strings that could be user-controlled
  • unserialize - used for strings that could contain a serialized string
  • include - used for strings that could contain a path beeing included
  • eval - used for strings that could contain code
  • ssrf - used for strings that could contain text passed to Curl or similar
  • file - used for strings that could contain a path
  • cookie - used for strings that could contain a http cookie
  • header - used for strings that could contain a http header
  • user_secret - used for strings that could contain user-supplied secrets
  • system_secret - used for strings that could contain system secrets

You're also free to define your own taint types when defining custom taint sources – they're just strings.

Taint Sources

Psalm currently defines three default taint sources: the $_GET, $_POST and $_COOKIE server variables.

You can also define your own taint sources.

Taint Sinks

Psalm currently defines a number of different for builtin functions and methods, including echo, include, header.

You can also define your own taint sinks.

Avoiding False-Positives

Nobody likes to wade through a ton of false-positives – here’s a guide to avoiding them.

Using Baseline With Taint Analysis

Since taint analysis is performed separately from other static code analysis, it makes sense to use a separate baseline for it.

You can use --use-baseline=PATH option to set a different baseline for taint analysis.

Viewing Results in a User Interface

Psalm supports the SARIF standard for exchanging static analysis results. This enables you to view the results in any SARIF compatible software, including the taint flow.

GitHub Code Scanning

GitHub code scanning can be set up by using the Psalm GitHub Action.

Alternatively, the generated SARIF file can be manually uploaded as described in the GitHub documentation.

The results will then be avaible in the "Security" tab of your repository.

Other SARIF compatible software

To generate a SARIF report run Psalm with the --report flag and a .sarif extension. For example:

psalm --report=results.sarif