security_doctor 0.7.0 copy "security_doctor: ^0.7.0" to clipboard
security_doctor: ^0.7.0 copied to clipboard

Security audit for Flutter and Dart apps: OWASP MASVS and CWE mapped checks for Dart code, configs and native manifests. Built for CI.

security_doctor #

pub package CI Buy me a coffee

Security audit for Flutter and Dart apps. Every rule maps to an OWASP MASVS requirement and a CWE id, so findings speak the language auditors already use. Built for CI: exit codes work like a test suite, reports come in console, JSON, Markdown and SARIF (GitHub Code Scanning) formats.

Want the same findings while you type? Add security_doctor_lints and the Dart rules show up right in your IDE, with quick fixes. The sibling package for dependency auditing is pubspec_doctor.

Quick start #

dart pub global activate security_doctor
security_doctor

Configuration #

Drop a security_audit.yaml next to your pubspec.yaml (all keys optional):

rules:
  SD002: false        # disable a rule
fail_on: high         # exit 1 only for findings at/above this severity
baseline: security_baseline.json  # optional; this is the default name
exclude:
  - lib/generated/**  # globs, relative to the project root

Severities are low, medium, high, critical; the default fail_on is low. The --fail-on CLI flag overrides the config, and --format picks the report: console (default), json, markdown or sarif.

Adopting on an existing project #

Snapshot the current findings once, commit the file, and only new findings will fail CI — historical debt stays visible (a "hidden" counter in every report) without blocking:

security_doctor --write-baseline   # writes security_baseline.json

Baseline entries match findings by a content hash (rule + file + normalized line), so they survive unrelated edits and line shifts. Delete the file or re-run --write-baseline to reset.

Suppressing a single finding #

For a deliberate exception, add an inline comment on the finding's line or the line above (any comment syntax — Dart, Gradle or XML):

final devUrl = 'http://intranet.corp/api'; // security_doctor: ignore SD002
<!-- security_doctor: ignore SD006 -->
<application android:allowBackup="true">

Several ids can be comma-separated. Suppressed findings are counted in every report, so exceptions stay visible.

Compliance mapping (PCI DSS, ISO 27001) #

--compliance regroups the report by requirements of a standard, in the language auditors ask in:

security_doctor --compliance pci-dss
security_doctor --compliance iso-27001 --format markdown

Requirements with no findings are listed as clean. The mapping is informative evidence for audit preparation — not a compliance verdict.

Id PCI DSS v4.0 ISO 27001:2022 Annex A
SD001 8.6.2 A.5.17, A.8.28
SD002 4.2.1 A.5.14, A.8.24
SD003 3.5.1 A.8.24
SD004 3.5.1, 4.2.1 A.8.24
SD005 4.2.1 A.5.14, A.8.24
SD006 6.5.6 A.8.9
SD007 7.2.1 A.8.9
SD008 3.3.1 A.8.15
SD009 6.2.4 A.8.28
SD010 6.5.6 A.8.9

GitHub Action #

- uses: actions/checkout@v5
- uses: PopovVA/security_doctor@v0
  with:
    fail-on: high
Input Default What it does
path . Project root containing pubspec.yaml.
fail-on from config Lowest severity that fails the build.
format console console, json or markdown.
upload-sarif false Send findings to GitHub Code Scanning.
sarif-file security_doctor.sarif Where the SARIF report is written.
args none Extra CLI arguments, e.g. --compliance iso-27001.
version latest Version constraint for the CLI, e.g. ^0.6.0.

It also sets exit-code as an output: 0 clean, 1 findings, 2 the run could not start.

GitHub Code Scanning #

Findings land in the Security tab next to the rest of your alerts, each one carrying its MASVS requirement and CWE id:

permissions:
  contents: read
  security-events: write

steps:
  - uses: actions/checkout@v5
  - uses: PopovVA/security_doctor@v0
    with:
      upload-sarif: true

The report is uploaded before the step fails, so an alert still appears on a red build. To collect findings without failing the build, add continue-on-error: true to the step.

Or drive the CLI yourself on any CI system:

- run: security_doctor --format sarif > security.sarif || true
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: security.sarif

Demo #

An intentionally vulnerable mini app lives in example/vulnerable_app — every rule fires on it:

security_doctor --path example/vulnerable_app

Rules #

Id Rule MASVS CWE
SD001 Hardcoded secrets and API keys in Dart code MASVS-STORAGE-1 CWE-798
SD002 Cleartext http:// URLs in code MASVS-NETWORK-1 CWE-319
SD003 Sensitive data in SharedPreferences MASVS-STORAGE-1 CWE-922
SD004 Weak cryptography (MD5, SHA1, ECB) MASVS-CRYPTO-1 CWE-327
SD005 usesCleartextTraffic / NSAllowsArbitraryLoads MASVS-NETWORK-1 CWE-319
SD006 android:debuggable / android:allowBackup MASVS-RESILIENCE-2 CWE-489
SD007 Dangerous Android permissions MASVS-PLATFORM-1 CWE-250
SD008 Sensitive data in print/log output MASVS-STORAGE-2 CWE-532
SD009 Release build without code shrinking (R8/ProGuard) MASVS-RESILIENCE-3 CWE-1269
SD010 get-task-allow in iOS/macOS entitlements MASVS-RESILIENCE-2 CWE-489

Exit codes #

Code Meaning
0 No findings at or above the severity threshold.
1 Findings at or above the threshold.
2 Usage or runtime error (e.g. no pubspec.yaml).

Support #

This package is free and maintained in my own time. If it saved you some, buy me a coffee.

License #

MIT

0
likes
160
points
478
downloads

Documentation

API reference

Publisher

verified publisherapissystems.dev

Weekly Downloads

Security audit for Flutter and Dart apps: OWASP MASVS and CWE mapped checks for Dart code, configs and native manifests. Built for CI.

Repository (GitHub)
View/report issues

Topics

#security #static-analysis #cli #ci #code-quality

License

MIT (license)

Dependencies

analyzer, args, crypto, glob, xml, yaml

More

Packages that depend on security_doctor