Heads up — this is early software. Pre-1.0 and actively developed. Rule packs, Psalm stubs, and the suppression list are still growing, so expect occasional false positives, the occasional rough edge in the web UI, and breaking changes between minor versions.

It's stable enough that we run it on our own UserSpice projects and ship its findings. It is not stable enough that you should wire it into a deploy gate without first pinning a specific version and running a baseline scan you trust.

Trust, but verify.

The prompts teach your AI assistant the framework's conventions. The skills enforce them as it writes. But assistants are pattern matchers — they'll occasionally produce code that looks right and has a real bug. The scanner is the third layer: it runs the same rules at a tool level, in containers, against your project's actual source, and tells you what it found.

Seven scanners — Semgrep, Psalm, Trivy, Gitleaks, ZAP, PHPStan, and a headers check — packaged as one bash entry point and an optional PHP web UI. All scanners run in Docker; nothing installs on your host other than Docker itself. The stack ships with UserSpice-aware rules, Psalm stubs, and suppressions so it understands the framework's helpers as safe sinks/sanitizers and stops flagging legitimate patterns.

What it is not

  • Not a code reviewer. It catches mechanical issues — SQL injection, missing CSRF, dependency CVEs, weak crypto. It can't tell you whether your business logic is correct, whether your data model makes sense, or whether your permissions actually map to your domain. Pair it with a human review for anything beyond the basics.
  • Not a security guarantee. Passing the scan means the code didn't trip these specific seven tools' rules. Novel attack patterns, business-logic flaws, and category errors the tools don't model still ship. "Clean scan" is a milestone, not a finish line.
  • Not a continuous-monitoring SaaS. No agents, no daemons, no telemetry leaving your machine. It runs on demand from your terminal, your CI, or a scheduled job you set up.
  • Not an IDE plugin. The web UI is a separate browser app, not inline editor feedback. For per-PR feedback, plug it into CI with --threshold and --diff so findings surface before merge.

What each tool catches

  • Semgrep — SQL injection, XSS, command injection, insecure crypto, framework-bypass patterns, DOM XSS in JS. Runs custom UserSpice rules first, then the community registry.
  • Psalm — PHP taint analysis. Traces user input through code to dangerous sinks (SQL, HTML, shell, file, SSRF). UserSpice stubs teach it which framework functions are safe sinks or sanitizers.
  • Trivy — CVEs in Composer and npm dependencies, plus misconfigurations and embedded secrets.
  • Gitleaks — hardcoded API keys, passwords, tokens, and credentials anywhere in the repo or git history.
  • ZAP (DAST) — runtime HTTP scanning. Three profiles: quick (passive only, ~3 min, safe anywhere), standard (active scan, local/staging only), deep (full active scan + Ajax spider, up to ~60 min, local only).
  • PHPStan — PHP code quality. Type errors, logic bugs, dead code, undefined variables. Complements Psalm's security focus.
  • Headers — security response headers (HSTS, CSP, X-Frame-Options, Permissions-Policy, Referrer-Policy, server exposure). Automatic when --url is provided.

How to install

Option A — Proxmox LXC (one command):

bash -c "$(wget -qO - https://raw.githubusercontent.com/mudmin/userspice-security-scanner/main/proxmox/install-lxc.sh)"

Creates an unprivileged Ubuntu 24.04 LXC with Apache, PHP, MariaDB, and Docker. Clones the scanner, pulls all scanner images, and prints the web UI URL when finished.

Option B — Manual install on any Linux:

git clone https://github.com/mudmin/userspice-security-scanner.git cd userspice-security-scanner ./setup.sh

Checks prerequisites (Docker, jq, bash 4+), asks where your projects live, and creates a gitignored scanner.conf with your local settings. Optionally pulls all Docker images on first run (~4 GB).

Option C — VirtualBox OVA: a self-contained appliance is in the build pipeline. Pre-built OVAs will be linked from this page when published.

How to use

After install the web UI is at http://localhost/codetest/ui/. Most day-to-day use happens there — browse projects, click Scan, view findings grouped by tool / rule / file, click any finding to see the flagged source line.

The CLI is available for CI/CD and scripting:

./scan.sh myproject # static scan ./scan.sh myproject --url http://localhost/myproject/ # static + ZAP + headers ./scan.sh myproject --threshold high # exit 1 on any HIGH+ finding (CI gate) ./scan.sh myproject --sarif # SARIF 2.1.0 output for GitHub ./scan.sh myproject --diff main # scan only files changed since main

What the output looks like

  • Per-tool finding lists with file, line, rule ID, severity, and the actual source snippet.
  • Owner tagging — each finding labeled project, userspice-core, userspice-customizable, or dependency so you know whether to fix it or report upstream.
  • Normalized severity across all tools (critical / high / medium / low / info).
  • Delta analysis — every scan compares against the previous one for the same project; new vs resolved findings shown in red/green.
  • Trends — chart of finding counts over time, severity breakdowns, clickable to drill into individual reports.
  • SARIF 2.1.0 export — upload to GitHub Code Scanning via the standard upload action.

Suppressions and rules

Framework-level truths belong in rules and stubs, not suppressions. The scanner ships custom Semgrep rules and Psalm stubs that teach the tools about UserSpice patterns (e.g. DB::query() is parameterized, safeReturn() escapes HTML, Input::get() sanitizes). Per-project suppressions go in overrides/<project>/, which is gitignored. Matching is by content-hash so suppression entries survive line shifts.

Plays well with the rest of the toolkit

  • AI Prompts — the prompts route your assistant around the failure modes the scanner catches. Use them together and the scanner has less to flag.
  • Claude skills/userspice-audit applies the same 12-rule checklist conversationally during development; the scanner runs the full seven-tool stack before you ship. Same philosophy, different vantage point.

Requirements

  • Linux or WSL2.
  • Docker — every scanner runs in a container.
  • jq, bash 4+ for the scan scripts.
  • PHP 8.0+ and Apache or Nginx for the web UI (optional — CLI works without).
  • Run ZAP against a copy of your site, not production. The deep profile sends tens of thousands of attack probes — it will create test accounts, fill every form with garbage, and trip WAFs.

Where the source lives

Source: github.com/mudmin/userspice-security-scanner.

Get help with the scanner

Want this installed, integrated with your CI, or run as a hosted scan against a copy of your site? Tell us what you need.

We reply within 1–2 business days.