Ward: The Laravel Security Scanner You Can’t Ignore

Laravel gives you a lot out of the box — CSRF protection, encrypted cookies, mass assignment guards, and more. But in real-world SaaS development, misconfigurations creep in. Secrets leak. Authorization gets skipped. And standard linters don’t catch it.

That’s where Ward comes in — a purpose-built security scanner for Laravel that understands your app’s structure and runs deep, contextual checks. It’s not just a grep tool. It’s a full-blown security pipeline with a beautiful terminal UI and CI integration.


🧠 What Makes Ward Different?

Ward doesn’t just scan files. It resolves your Laravel project — routes, models, controllers, Blade templates, config files, environment variables, Composer dependencies — and then runs targeted security checks.

It catches what other tools miss:

  • APP_DEBUG=true in production
  • Controllers missing authorize()
  • $guarded = [] on sensitive models
  • DB::raw() with interpolated user input
  • Session cookies without Secure flag
  • Blade templates using {!! !!} on user data
  • Outdated Composer packages with known CVEs
  • API routes missing auth:sanctum middleware

Ward is designed to fit into your workflow — run it locally during development or wire it into CI to gate deployments.


🔍 How Ward Works: 5-Stage Pipeline

Ward’s architecture is clean and modular:

  1. Provider — Locates and prepares your project (local path or git URL).
  2. Resolvers — Parses .env, composer.json, config/*.php to build a structured context.
  3. Scanners — Runs independent security checks across environment, config, dependencies, and custom rules.
  4. Post-Process — Deduplicates findings, filters by severity, diffs against previous scans.
  5. Report — Generates output in JSON, SARIF, HTML, and Markdown formats.

This pipeline ensures deep, contextual analysis — not just surface-level pattern matching.


🛡️ Built-In Scanners

Ward ships with four powerful scanners:

ScannerWhat It Checks
env-scanner.env misconfigurations — debug mode, missing keys, leaked secrets
config-scannerconfig/*.php — insecure defaults, hardcoded credentials, missing flags
dependency-scannercomposer.lock — live CVE lookup via OSV.dev against Packagist advisories
rules-scanner42 YAML rules covering secrets, injection, XSS, debug artifacts, crypto, auth

These scanners cover the most common — and most dangerous — Laravel security pitfalls.


🧪 Example: Detecting Dangerous Defaults

Let’s say your app has this in production:

// .env
APP_DEBUG=true
APP_KEY=

Ward flags both as critical issues:

  • ENV-002: Debug mode enabled in production
  • ENV-003: Empty or missing APP_KEY

It also checks for:

  • Weak default keys
  • Real credentials in .env.example
  • File-based sessions in production
  • Unsecured cookies and CORS wildcards

These are the kinds of issues that slip through manual review — but Ward catches them instantly.


📦 Composer CVE Scanning

Ward reads your composer.lock as a software bill of materials (SBOM) and queries the OSV.dev vulnerability database in real time.

It covers:

  • Laravel
  • Symfony
  • Guzzle
  • Doctrine
  • Monolog
  • Livewire
  • Filament
  • Every other Packagist dependency

Results include CVE IDs, severity, affected versions, fixed versions, and remediation commands. This is live CVE scanning — not a hardcoded list.


🧰 Custom Rules with YAML

Want to scan for hardcoded internal URLs?

- id: TEAM-001
  title: "Hardcoded internal service URL"
  description: "Detects hardcoded URLs to internal services."
  severity: medium
  category: Configuration
  enabled: true
  patterns:
    - type: regex
      target: php-files
      pattern: 'https?://internal-service\\.\\w+'
  remediation: |
    Use environment variables: $url = env('INTERNAL_SERVICE_URL');

Drop this into ~/.ward/rules/ and Ward picks it up automatically. No recompilation needed.


📈 Scan History & Diffing

Ward saves every scan to ~/.ward/store/. On subsequent scans, it shows:

[info] vs last scan: 2 new, 3 resolved (12→11)

This lets you track your security posture over time and catch regressions before they ship.


🖥️ Beautiful Terminal UI

Ward’s TUI (built with Bubble Tea) adapts to light and dark terminals. It shows:

  • Live scan progress
  • Severity counts
  • Scrollable event log
  • Sortable findings table
  • Detail panel with code snippet, remediation, and references

It’s fast, intuitive, and developer-friendly.


⚙️ CI Integration

Ward fits into your CI pipeline with ease:

GitHub Actions:

- name: Run Ward
  run: ward scan . --output json

- name: Upload SARIF
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: ward-report.sarif

GitLab CI:

ward-scan:
  image: golang:latest
  script:
    - go install github.com/eljakani/ward@latest
    - ward init && ward scan . --output json
  artifacts:
    paths:
      - ward-report.*
    when: always

You can gate deployments based on severity, track trends, and upload SARIF reports for GitHub Code Scanning.


🧠 Philosophy: Interface-First, Event-Driven

Ward’s architecture is built around:

  • Interfaces — every component is a Go interface
  • EventBus — scanners emit findings, TUI subscribes
  • Shared Context — resolvers build once, scanners consume
  • Rules as Data — YAML rules, no recompilation

This makes it extensible, testable, and future-proof.


🔮 Roadmap Highlights

  • AI-assisted scanning
  • Policy engine for CI pass/fail thresholds
  • More resolvers: routes, models, controllers, middleware
  • PHP AST-based scanning
  • Per-project .ward.yaml config

Ward is already powerful — but its roadmap shows it’s just getting started.


Final Thoughts

Ward isn’t just a scanner. It’s a security orchestration engine for Laravel.

It understands your app’s structure, runs deep contextual checks, and fits into your workflow — from local dev to CI pipelines.

If you’re building Laravel apps in 2026, Ward is the tool that helps you ship secure by default.

Leave a Reply

Your email address will not be published. Required fields are marked *