Psalm Integration with DefectDojo
Psalm Integration with DefectDojo
Psalm is a free, open source static analysis tool for PHP, originally developed at Vimeo and hosted in the vimeo/psalm GitHub repository. It infers types across a codebase and reports problems such as type mismatches, possible null references, and dead code, and it can fix some issue types automatically. Psalm reads its configuration from psalm.xml, where an errorLevel decides how strict the analysis is, and it can write results in several report formats, including SARIF.
Psalm Integration with DefectDojo
We run Psalm on our PHP services because type errors are where a lot of real defects hide in a dynamically typed language, and some of them become security bugs. Importing Psalm's SARIF output into DefectDojo turns each reported issue into a Finding on the right Asset, titled with the Psalm issue type our developers already recognize from psalm.xml and baselines. Rescans deduplicate against what is already open, fixes close on reimport, and the PHP code findings sit in the same reports as our dependency and container results instead of in a separate CI log.
Why Psalm Matters
PHP lets a lot of mistakes reach production quietly. Psalm catches many of them before deployment by reasoning about types the language itself does not enforce.
- It reports impossible comparisons, possibly null values, and unreachable code that tests often miss.
- Issue types are named and documented, so a developer can look up exactly why something was flagged.
- Strictness is configurable per project through
errorLevel, so a legacy codebase can adopt Psalm gradually. - Its SARIF output fits into any tool that reads the standard, but a SARIF file has no memory of which issues were already triaged.
Advantages of This Integration
What DefectDojo adds on top of Psalm:
- Titles developers recognize. Each Finding is titled with Psalm's issue type followed by the message, for example
TypeDoesNotContainType: string cannot be identical to int. - Tracking by issue type. The parser stores the issue type as the vuln ID from tool, which keeps deduplication tied to the rule rather than Psalm's numeric shortcode.
- Deduplication that survives rescans. DefectDojo matches on a SARIF fingerprint when the report provides one, and otherwise hashes the issue type, file path, and line.
- Lifecycle on reimport. Reimporting the next report into the same Test mitigates issues that were fixed and adds new ones.
- Suppressions respected. SARIF results that carry a suppression are imported as false positives and inactive, so they do not count against SLAs.
- The usual workflow. Findings can be assigned, commented on, risk-accepted, and pushed to Jira like results from any other scanner.
How This Integration Works
DefectDojo imports Psalm results with the Psalm Scan scan type. It reuses DefectDojo's shared SARIF parsing with Psalm-specific title and identifier handling.
1. Produce a SARIF report. From the project root, with your normal psalm.xml in place:
psalm --report=results.sarif
Psalm also offers a taint analysis mode for security issues. If you use it, write its results to SARIF the same way and import them with the same scan type; code flows present in the SARIF are added to the Finding description.
2. Import the report. In the UI, open the Engagement, choose Import Scan Results, select Psalm Scan, and upload results.sarif. With the API, in Community Edition or DefectDojo Pro:
curl "https://YOUR_INSTANCE/api/v2/import-scan/"
-H "Authorization: Token $DD_API_TOKEN"
-F "scan_type=Psalm Scan"
-F "file=@results.sarif"
-F "product_name=storefront"
-F "engagement_name=CI"
-F "auto_create_context=true"
DefectDojo Pro users can run the import from a pipeline with Universal Importer:
universal-importer import
--defectdojo-url "https://YOUR_INSTANCE.cloud.defectdojo.com/"
--scan-type "Psalm Scan"
--report-path "./results.sarif"
--product-name "storefront"
--engagement-name "CI"
--auto-create-context
3. Reimport on every run. Later reports go to /api/v2/reimport-scan/ against the same Test, so the history of each issue stays in one place.
Data Granularity: What Gets Imported
| DefectDojo Field | Source in Psalm SARIF | Notes |
|---|---|---|
| Title | Rule name and result message |
Issue type first, then the message |
| Severity | SARIF level |
error becomes High, note becomes Info |
| Description | Result message, snippet, rule name and descriptions | Ends with the Psalm shortcode; code flows added when present |
| File Path | artifactLocation.uri |
One Finding per reported location |
| Line | region.startLine |
Start line of the issue |
| Vuln ID From Tool | Rule name |
The Psalm issue type, replacing the numeric ruleId |
| References | Rule helpUri |
Link to the Psalm documentation page for the issue |
| Tags | Rule and result property tags | For example maintainability |
| Date | Invocation end time | When the SARIF run records one |
| Active / False Positive | SARIF suppressions | Suppressed results import as inactive false positives |
| Finding type | Static | All Psalm findings are marked static |
| Deduplication | Unique ID or hashcode | Fingerprint if present, else vuln ID from tool, file path, line |
Psalm does not report CWE values, so imported Findings have no CWE.
Use Cases
In CI for a PHP monolith: Each merge request runs Psalm and the main branch reimports into one Test. Developers see the issues their change introduced, and the security team sees the overall count trend down release by release.
Adopting Psalm on legacy code: A team starts at a lenient errorLevel, imports the first report as a baseline, and risk-accepts known categories with an expiration date while they tighten the configuration.
Tracking taint results separately: Teams that run Psalm's taint analysis can import it into its own Test in the same Engagement, which keeps security-relevant flows apart from general type issues while both stay on the Asset.
Portfolio reporting: Organizations with many PHP services get one view of open Psalm findings by Asset, next to SCA and DAST results for the same applications.
Operational Tips
- Severity follows your
psalm.xml. The same code can import as High in a strict project and Info in a lenient one, so keeperrorLevelstable if you rely on SLAs. - Psalm has only two levels, so expect most results at High or Info. Use
minimum_severity=Highon import if Info-level issues would crowd out what matters. - Line numbers are part of the fallback hash. Large refactors can close old Findings and open new ones for the same issue.
- Keep Psalm's own baseline file and DefectDojo in agreement. Issues you baseline in Psalm will not appear in the report and will be mitigated on reimport.
- Filter on vuln ID from tool to work through one issue type at a time, such as every
PossiblyNullReferencein a service. - Tag imports with the branch or release so you can compare Psalm results between versions.