PHPackages                             intentphp/guard - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. intentphp/guard

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

intentphp/guard
===============

A Laravel CLI tool that scans your application for common security risks: authorization gaps, unsafe query input, and mass assignment vulnerabilities.

v2.1.0(1mo ago)017MITPHPPHP ^8.2CI passing

Since Feb 13Pushed 1mo agoCompare

[ Source](https://github.com/drnasin/intentphp)[ Packagist](https://packagist.org/packages/intentphp/guard)[ RSS](/packages/intentphp-guard/feed)WikiDiscussions main Synced today

READMEChangelog (4)Dependencies (17)Versions (18)Used By (0)

IntentPHP Guard
===============

[](#intentphp-guard)

[![Tests](https://github.com/drnasin/intentphp/actions/workflows/tests.yml/badge.svg)](https://github.com/drnasin/intentphp/actions/workflows/tests.yml)[![Latest Version](https://camo.githubusercontent.com/d546897a03feb8ab671106769bfc36327e09157dca402b16c676af824c89f5b9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f64726e6173696e2f696e74656e747068703f646973706c61795f6e616d653d74616726736f72743d73656d766572)](https://github.com/drnasin/intentphp/releases)[![PHP](https://camo.githubusercontent.com/0574690185ec7275fd5479762a504f10ff4f57e84ef7fcfbd5a406df72945779/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d382e322532422d383839324246)](https://php.net)[![Laravel](https://camo.githubusercontent.com/8077066fd4ee824e023537911f8c554788bae61b148aaf920bac1010dc5bc040/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d31302532302537432532303131253230253743253230313225323025374325323031332d464632443230)](https://laravel.com)[![License](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](LICENSE)

A Laravel CLI tool that scans your application for common security risks: authorization gaps, unsafe query input, and mass assignment vulnerabilities.

Why Guard?
----------

[](#why-guard)

Most static analysis tools answer:
**“Is this code valid?”**

Guard answers a different question:
**“Does this code match the security and data-handling intent of this project?”**

Guard introduces an optional **intent specification** (`intent/intent.yaml`) where you declare expected security and data rules — for example:

- which routes must be authenticated
- which guards must be used
- which models must use explicit `$fillable`
- which attributes must never be mass-assignable

Guard then scans your code and reports mismatches between:

> declared intent vs actual implementation

This makes Guard especially useful in CI pipelines, security-sensitive Laravel applications, and multi-developer teams where architectural and security rules must stay enforced over time.

Guard is:

- ✅ additive — no breaking changes without intent spec
- ✅ deterministic — stable fingerprints and reproducible results
- ✅ CI-safe — predictable exit codes and output
- ✅ non-invasive — never modifies your code

Comparison With Other Tools
---------------------------

[](#comparison-with-other-tools)

Tool typeExamplesWhat they focus onHow Guard differsStatic analysisPHPStan, LarastanType safety, code correctness, API misuseGuard does not check types — it enforces **security and data invariants**Security scanners (SAST)Semgrep, CodeQL, SonarPattern-based vulnerability detectionGuard uses a **project intent spec** — rules come from your declared policy, not a global pattern databaseLaravel lintersPint, style toolsCode style and formattingGuard does not enforce style — it focuses on **auth and data-safety rules**Config / policy scannersCI security checkersKnown misconfiguration patternsGuard validates your **declared security model** against actual code behaviorRuntime protectionWAF, middlewareRuntime request filtering and blockingGuard runs **before deploy**, in CI, as static policy validationQuick Start
-----------

[](#quick-start)

```
composer require intentphp/guard --dev
php artisan guard:baseline
php artisan guard:scan --baseline --strict
```

Add the last command to CI — Guard will now fail builds only on **new** security risks.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 10, 11, 12, or 13

Installation
------------

[](#installation)

Install Guard as a dev dependency:

```
composer require intentphp/guard --dev
```

The service provider is auto-discovered. Optionally publish the config:

```
php artisan vendor:publish --tag=guard-config
```

Commands
--------

[](#commands)

### `guard:scan` — Scan for security issues

[](#guardscan--scan-for-security-issues)

```
# Default: console table output, all severities
php artisan guard:scan

# JSON output, high severity only
php artisan guard:scan --format=json --severity=high

# GitHub Actions annotation output (for CI)
php artisan guard:scan --format=github

# Markdown output (for PR comments)
php artisan guard:scan --format=md

# Include AI-generated fix suggestions
php artisan guard:scan --ai

# Incremental: scan only files changed vs base branch
php artisan guard:scan --changed

# Incremental: explicit base ref
php artisan guard:scan --changed --base=origin/main

# Incremental: staged files only (pre-commit hook)
php artisan guard:scan --staged

# Incremental: compare against a specific ref
php artisan guard:scan --changed-since=v1.2.0

# Save report to a file (json or md format)
php artisan guard:scan --format=md --output=storage/guard/report.md
php artisan guard:scan --format=json --output=storage/guard/report.json

# Use baseline to suppress known findings
php artisan guard:scan --baseline

# Strict mode: fail if baseline file is missing
php artisan guard:scan --baseline --strict

# Show suppressed findings in output
php artisan guard:scan --include-suppressed

# Limit displayed findings
php artisan guard:scan --max=20

# Include AI patch proposals in JSON output
php artisan guard:scan --format=json --ai --include-ai-patch
```

**Exit codes:**

- `0` — No active HIGH severity findings
- `1` — Active HIGH severity findings exist
- `2` — Baseline file missing (with `--strict`)

### `guard:baseline` — Save current findings as baseline

[](#guardbaseline--save-current-findings-as-baseline)

```
# Baseline all findings
php artisan guard:baseline

# Baseline only HIGH findings
php artisan guard:baseline --severity=high
```

Saves a fingerprint snapshot to `storage/guard/baseline.json`. Future scans with `--baseline` will suppress any findings that match the saved fingerprints.

This is the recommended workflow for adopting Guard on an existing codebase:

1. Run `php artisan guard:baseline` to snapshot current state
2. Add `php artisan guard:scan --baseline --strict` to CI
3. CI will now only fail on **new** findings, not existing ones
4. Fix existing findings at your own pace

### `guard:fix` — Generate safe patch proposals

[](#guardfix--generate-safe-patch-proposals)

```
# Template-based patches
php artisan guard:fix

# Include AI-assisted patches for findings where templates fail
php artisan guard:fix --ai

# Fix only changed files
php artisan guard:fix --changed
php artisan guard:fix --staged
php artisan guard:fix --changed --base=origin/main
```

Generates `.diff` files in `storage/guard/patches/` for each HIGH severity finding. With `--ai`, falls back to AI-generated patches when templates cannot produce a diff. AI patches are marked with a header comment. When AI returns guidance that cannot be structured as a diff, a `.md` note file is written instead.

> **Warning:** Always review patches before applying. Guard never guarantees semantic correctness of generated diffs.

Patches are never applied automatically — review and apply manually:

```
git apply storage/guard/patches/001_route_authorization_OrderController_L25.diff
```

**Exit codes:**

- `0` — No patches generated (clean scan)
- `1` — Patches were generated (findings exist)

### `guard:apply` — Validate and apply a patch

[](#guardapply--validate-and-apply-a-patch)

```
# Validate a patch file (dry-run)
php artisan guard:apply storage/guard/patches/001_route_authorization_OrderController_L25.diff

# Also accepts just the filename (resolves from storage/guard/patches/)
php artisan guard:apply 001_route_authorization_OrderController_L25.diff
```

Checks if a patch applies cleanly using `git apply --check` and shows the command to apply it. Never applies patches automatically.

### `guard:testgen` — Generate security tests

[](#guardtestgen--generate-security-tests)

```
# Generate tests (skip existing files)
php artisan guard:testgen

# Overwrite existing generated tests
php artisan guard:testgen --overwrite
```

Generates PHPUnit tests in `tests/Feature/GuardGenerated/`:

- `RouteAuthorizationTest.php` — guest access assertions
- `DangerousInputValidationTest.php` — malicious input regression tests
- `MassAssignmentProtectionTest.php` — model protection assertions

### `guard:intent` — Manage the intent spec

[](#guardintent--manage-the-intent-spec)

```
# Scaffold a starter intent/intent.yaml
php artisan guard:intent init

# Validate an existing intent spec
php artisan guard:intent validate

# Show parsed spec summary
php artisan guard:intent show

# Build spec↔code mapping index (summary)
php artisan guard:intent map

# Dump deterministic mapping JSON
php artisan guard:intent map --dump
```

Manages the optional `intent/intent.yaml` spec file. `init` generates a starter file with example auth rules and model declarations. `validate` checks the spec for parse and schema errors. `show` prints a summary of the parsed spec. `map` builds a mapping index between spec rules and code targets (routes, models). If the intent spec is missing, `map` produces an observed-only index containing routes only (no models). The intent spec is optional — Guard works without it.

### `guard:doctor` — Environment diagnostics

[](#guarddoctor--environment-diagnostics)

```
php artisan guard:doctor
```

Runs a series of environment checks and prints a diagnostic report with actionable guidance. Useful for verifying your setup after installation or troubleshooting issues.

**Checks performed:**

SectionWhat it verifiesLaravel Context`artisan` file exists (confirms Laravel project)Storage / Writable`storage/guard/`, `cache/`, and `patches/` directories are writableGit`git` binary available and project is a git repositoryBaselineWhether a baseline suppression file existsAI DriverAI configuration, CLI tool availability, API key presenceCacheCache enabled/disabled status and path**Exit codes:**

CodeMeaning`0`No blocking errors (warnings are OK)`1`Blocking errors found (e.g., storage not writable, not a Laravel app)**Example output:**

```
IntentPHP Guard — Environment Diagnostics
==========================================

Laravel Context
  [OK]    Artisan file found at /var/www/app/artisan

Storage / Writable
  [OK]    storage/guard/ is writable
  [OK]    storage/guard/cache/ is writable
  [OK]    storage/guard/patches/ is writable

Git
  [OK]    git binary found (git version 2.43.0)
  [OK]    Repository detected — incremental scanning available.

Baseline
  [WARN]  No baseline file found. Run: php artisan guard:baseline

AI Driver
  [OK]    AI is disabled. Enable with GUARD_AI_ENABLED=true.

Cache
  [OK]    Cache enabled. Path: storage/guard/cache
  [OK]    Tip: use --no-cache with guard:scan to bypass cache for a single run.

──────────────────────────────────────────
Result: 0 error(s), 1 warning(s) — all clear!

```

Checks
------

[](#checks)

### 1. Route Authorization Coverage

[](#1-route-authorization-coverage)

Detects routes missing auth middleware or authorization calls. Checks route-level and group-level middleware, `$this->authorize()`, `Gate::` calls, `authorizeResource()` in constructors, and FormRequest type hints. Enriched with Project Map context (model, policy, ability).

### 2. Dangerous Request Input in Queries

[](#2-dangerous-request-input-in-queries)

AST-based detection of request input flowing into query builder sinks. Catches `whereRaw`, `orderByRaw`, `havingRaw`, `groupByRaw`, `selectRaw`, `fromRaw`, the column position of `orderBy` / `where` / `whereColumn`, and the `DB` facade family (`raw`, `statement`, `select`, `selectOne`, `insert`, `update`, `delete`, `unprepared`).

Coverage extends beyond the literal `->whereRaw($request->...)` form. The check sees:

- multi-line calls (formatting-independent);
- string interpolation and concatenation embedding request input: `whereRaw("id = {$request->input('id')}")`, `'..' . $request->q`;
- one-hop variable indirection (monotonic per-function taint): `$dir = $request->input('dir'); …->orderByRaw("name $dir")`;
- request access through a FormRequest-typed parameter (any class under `*\Http\Requests\*`).

`->where('col', $request->x)` is recognised as a safe parameterized binding and is **not** flagged. `->orderBy($sort)` based purely on a sort-like variable name is reported as MEDIUM (since the value may be validated) — it never gates CI.

### 3. Mass Assignment Risk

[](#3-mass-assignment-risk)

Detects bulk request input flowing into mass-assignment sinks: `Model::create(...)` and `->update(...)` / `->fill(...)`. Bulk input is `$request->all()`, argless `$request->input()`, `$request->except()`, or `$request->validated()` (the last is MEDIUM). One-hop variable indirection (`$d = $request->all(); $m->fill($d);`) is caught via the same per-function taint analysis as check #2.

A model is treated as mass-assignable when:

- `$guarded = []` (everything open), or
- `$guarded` is set to a non-`['*']` partial allowlist **and** there is no `$fillable`.

A bare Eloquent model (no `$fillable` and no `$guarded`) inherits the framework default `$guarded = ['*']` and is **not** flagged. Likewise, an explicit `$guarded = ['*']` or any `$fillable` allowlist is treated as safe.

### 4. Intent Auth (`intent-auth`)

[](#4-intent-auth-intent-auth)

Compares actual route middleware against requirements declared in the intent spec. Detects routes that should be authenticated, require a specific guard, or are declared public but lack auth middleware. Only active when `intent/intent.yaml` is present and contains `auth.rules`.

### 5. Intent Mass Assignment (`intent-mass-assignment`)

[](#5-intent-mass-assignment-intent-mass-assignment)

Checks model files against mass-assignment constraints declared in the intent spec. Detects models missing `$fillable` when declared as `explicit_allowlist`, forbidden attributes present in `$fillable`, and empty `$guarded` when declared as `guarded` mode. Only active when `intent/intent.yaml` is present and contains `data.models`.

Intent checks are additive. A route can receive both a `route-authorization` finding and an `intent-auth` finding. They serve different purposes (config-driven vs spec-driven) and are independently suppressible via baseline or inline ignores.

### 6. Intent Drift (`intent-drift/auth`, `intent-drift/mass-assignment`)

[](#6-intent-drift-intent-driftauth-intent-driftmass-assignment)

Detects divergence between declared intent and observed project state. Auth drift detects missing auth middleware, missing guard middleware, and public routes with unnecessary auth middleware. Mass-assignment drift detects missing `$fillable`, forbidden attributes in `$fillable`, empty `$guarded`, and unparseable model patterns. Drift findings have stable fingerprints and integrate with baseline suppression. Only active when `intent/intent.yaml` is present.

### 7. Spec↔Code Mapping (`guard:intent map`)

[](#7-speccode-mapping-guardintent-map)

Builds a versioned mapping index (v1.0) linking spec rules to code targets (routes and models). Each entry is classified as `spec_linked` (matched by an intent rule) or `observed_only` (no spec coverage). The mapping is used internally by the drift engine for context enrichment and can be dumped as deterministic JSON via `guard:intent map --dump`. If the intent spec is missing, the mapping contains routes only (no models).

Intent Spec (optional)
----------------------

[](#intent-spec-optional)

Guard supports an optional `intent/intent.yaml` file at the project root. This file declares expected security properties (auth rules, model constraints) that Guard validates against your actual code.

- If the file is missing, Guard behaves exactly as before. No configuration needed.
- If the file is present and valid, additional `intent-auth` and `intent-mass-assignment` checks run alongside existing checks.
- If the file has parse errors or validation failures, Guard prints the errors and exits non-zero.
- This is fully additive. No existing behavior changes.

### Setup

[](#setup)

```
# Scaffold a starter intent spec
php artisan guard:intent init

# Run scan (intent checks activate automatically if spec exists)
php artisan guard:scan
```

### Minimal example

[](#minimal-example)

```
version: "0.1"
project:
  name: my-app
  framework: laravel

auth:
  guards:
    api: token
  rules:
    - id: api-protected
      match:
        routes:
          prefix: /api
      require:
        authenticated: true
        guard: api

data:
  models:
    App\Models\User:
      massAssignment:
        mode: explicit_allowlist
        allow: [name, email]
        forbid: [is_admin]
```

### Warnings

[](#warnings)

If the intent spec references a model whose file cannot be found on disk, Guard prints a warning and continues. Warnings do not produce findings and do not cause the scan to fail. The scan only fails if the spec itself is structurally invalid.

Inline Suppressions
-------------------

[](#inline-suppressions)

Suppress individual findings by adding a comment on the same line or the line above:

```
// guard:ignore dangerous-query-input
->orderBy($request->input('sort'))

->orderBy($request->input('sort')) // guard:ignore dangerous-query-input

// guard:ignore all
->whereRaw($request->input('filter'))
```

Suppressed findings are tracked and shown in the summary. Disable inline ignores in config:

```
'allow_inline_ignores' => false,
```

Configuration
-------------

[](#configuration)

```
// config/guard.php

return [
    // Structured (recommended). The legacy flat 'auth_middlewares' key still
    // works for backward compatibility but is deprecated.
    'route_authorization' => [
        'auth_middleware_exact' => [
            'auth',
            'auth:sanctum',
            'Filament\\Http\\Middleware\\Authenticate',
        ],
        // 'auth' matches both auth:sanctum and auth.basic (dotted aliases).
        'auth_middleware_prefixes' => ['auth'],
        // Any FQCN ending in \Authenticate (namespace-anchored) counts as auth,
        // so custom App\Http\Middleware\Authenticate is recognised by default.
        'auth_middleware_suffixes' => ['\\Authenticate'],

        // Framework-standard guest routes Guard skips by default.
        'skip_guest_routes' => ['login', 'register', 'forgot-password', /* ... */],
        // Framework-standard infrastructure routes Guard skips by default.
        'skip_infra_routes' => ['up', 'health', 'sanctum/csrf-cookie', 'livewire/*', /* ... */],
    ],

    // Business-specific public routes (in addition to the skip lists above).
    'public_routes' => [],

    'ai' => [
        'enabled' => env('GUARD_AI_ENABLED', false),
        'driver' => env('GUARD_AI_DRIVER', 'null'), // null|cli|openai|auto

        'cli' => [
            'command' => env('GUARD_AI_CLI', 'claude'),
            'args' => env('GUARD_AI_CLI_ARGS', ''),
            'timeout' => env('GUARD_AI_CLI_TIMEOUT', 60),
            'expects_json' => env('GUARD_AI_CLI_JSON', false),
            'adapter' => env('GUARD_AI_CLI_ADAPTER', 'auto'),
            'prompt_prefix' => env('GUARD_AI_CLI_PROMPT_PREFIX', ''),
        ],

        'openai' => [
            'base_url' => env('GUARD_AI_BASE_URL', 'https://api.openai.com/v1'),
            'api_key' => env('GUARD_AI_API_KEY', ''),
            'model' => env('GUARD_AI_MODEL', 'gpt-4.1-mini'),
            'timeout' => env('GUARD_AI_TIMEOUT', 30),
            'max_tokens' => env('GUARD_AI_MAX_TOKENS', 1024),
        ],
    ],

    'cache' => [
        'enabled' => env('GUARD_CACHE_ENABLED', true),
    ],

    'allow_inline_ignores' => true,
];
```

Incremental Scanning
--------------------

[](#incremental-scanning)

Guard can scan only files that changed in your working tree, dramatically speeding up scans in large projects and CI pipelines.

### Modes

[](#modes)

FlagWhat it scans`--changed`Files changed vs auto-detected base branch`--changed --base=REF`Files changed vs the given ref`--staged`Only staged files (ideal for pre-commit hooks)`--changed-since=REF`Files changed since a specific commit/tagBase branch auto-detection tries: `origin/main` → `origin/master` → `main` → `master` → `HEAD~1`. If your default branch is `master`, use `--base=origin/master` to skip auto-detection.

Route authorization check runs in one of three modes:

- **full** — when route files changed or no incremental mode is active
- **filtered** — when only controller files changed (only related routes are checked)
- **skipped** — when neither routes nor controllers changed

File-based checks (dangerous query input, mass assignment) are filtered to only the changed files.

### Pre-commit hook example

[](#pre-commit-hook-example)

```
#!/bin/sh
php artisan guard:scan --staged --severity=high --format=github
```

### CI with incremental scan

[](#ci-with-incremental-scan)

```
- name: Run Guard scan (incremental)
  run: php artisan guard:scan --changed --base=origin/main --format=github --severity=high
```

Caching
-------

[](#caching)

Guard caches expensive computations (Project Map, reflection results) to speed up repeated scans. The cache is stored in `storage/guard/cache/` and invalidated automatically when:

- The git HEAD SHA changes (new commits), when available
- The PHP or Laravel version changes
- Relevant file modification times change (routes, controllers, policies, kernel, auth provider) — used as fallback when git SHA is unavailable

### Configuration

[](#configuration-1)

Caching is enabled by default. To disable:

```
GUARD_CACHE_ENABLED=false
```

### Clearing the cache

[](#clearing-the-cache)

```
rm -rf storage/guard/cache/
```

The cache is safe to delete at any time — Guard will rebuild it on the next scan.

You can bypass the cache for a single run with `--no-cache`:

```
php artisan guard:scan --no-cache
```

Performance Notes
-----------------

[](#performance-notes)

- **Full scan**: analyzes routes + controllers + models (every PHP file in scope)
- **Incremental scan**: analyzes only changed files, with route check filtering based on what changed
- **With caching enabled**, repeated scans are typically 3-10x faster (Project Map and reflection results are cached)

Report Output
-------------

[](#report-output)

### Saving reports to file

[](#saving-reports-to-file)

Use `--output` with `--format=json` or `--format=md` to save the report to a file:

```
# Markdown report file
php artisan guard:scan --format=md --output=report.md

# JSON report file
php artisan guard:scan --format=json --output=report.json
```

The `--output` option is supported for `json` and `md` formats. Console format (`--format=console`) does not support file output. When `--output` is set, Guard writes the report to the file and prints a short confirmation line to the console.

### AI Setup (Local CLI)

[](#ai-setup-local-cli)

Guard uses locally installed AI CLI tools (e.g. `claude`, `codex`) to generate fix suggestions. No API keys needed for local usage.

**Quick start (macOS / Linux):**

```
# .env
GUARD_AI_ENABLED=true
GUARD_AI_DRIVER=auto
```

**Quick start (Windows PowerShell):**

```
$env:GUARD_AI_ENABLED="true"
$env:GUARD_AI_DRIVER="auto"
php artisan guard:scan --ai
```

The `auto` driver tries in order: local CLI tool in PATH, then OpenAI API (if key set), then falls back gracefully to no AI (scan still works, just without suggestions).

**Explicit CLI configuration:**

```
GUARD_AI_ENABLED=true
GUARD_AI_DRIVER=cli
GUARD_AI_CLI=claude
GUARD_AI_CLI_ARGS="--print"
GUARD_AI_CLI_TIMEOUT=60
```

**Using a different CLI tool:**

```
GUARD_AI_CLI=codex
GUARD_AI_CLI_ADAPTER=codex
```

**Using any custom CLI:**

```
GUARD_AI_CLI=/usr/local/bin/my-ai-tool
GUARD_AI_CLI_ADAPTER=generic
GUARD_AI_CLI_ARGS="--stdin --format text"
```

**JSON output mode** — If your CLI supports structured JSON output with `suggestion` and `patch` keys, enable it for richer results:

```
GUARD_AI_CLI_JSON=true
GUARD_AI_CLI_ARGS="--output-format json"
```

### AI Setup (OpenAI API)

[](#ai-setup-openai-api)

For CI pipelines or environments without a local CLI tool, use the OpenAI HTTP driver:

```
GUARD_AI_ENABLED=true
GUARD_AI_DRIVER=openai
GUARD_AI_API_KEY=sk-your-key-here
```

**Compatible with any OpenAI-compatible API** — Azure OpenAI, Ollama, LM Studio, local vLLM, etc.:

```
GUARD_AI_BASE_URL=http://localhost:11434/v1
GUARD_AI_MODEL=llama3
```

VariableDefaultDescription`GUARD_AI_API_KEY`*(empty)*API key (required for `openai` driver)`GUARD_AI_BASE_URL``https://api.openai.com/v1`API base URL`GUARD_AI_MODEL``gpt-4.1-mini`Model name`GUARD_AI_TIMEOUT``30`Request timeout in seconds`GUARD_AI_MAX_TOKENS``1024`Max tokens in responseThe client retries once on 429 (rate limit) and 5xx errors. API key is never logged.

### AI Driver Priority (`auto`)

[](#ai-driver-priority-auto)

When using `GUARD_AI_DRIVER=auto`, Guard selects the best available driver:

1. **CLI** — local `claude`/`codex` binary in PATH (free, no API cost)
2. **OpenAI** — API key set in `GUARD_AI_API_KEY`
3. **Null** — no AI, scan works normally without suggestions

This means `auto` works everywhere: locally with a CLI tool, in CI with an API key, or gracefully without either.

### Troubleshooting AI

[](#troubleshooting-ai)

ProblemCauseFix"CLI command not found in PATH"Binary not installed or not in PATHInstall the CLI tool, or set full path in `GUARD_AI_CLI`"exited with code N"CLI tool returned an errorCheck `storage/logs/laravel.log` for stderr outputTimeoutAI took too longIncrease `GUARD_AI_CLI_TIMEOUT` (default: 60s)Empty outputCLI didn't write to stdoutCheck that your CLI args are correctScan works but no suggestionsAI not enabledSet `GUARD_AI_ENABLED=true` and `GUARD_AI_DRIVER=auto`"AI request failed after retries"API returned errorsCheck `storage/logs/laravel.log` for HTTP status and body"GUARD\_AI\_API\_KEY not set"Missing API keySet `GUARD_AI_API_KEY` in `.env`### Security Note

[](#security-note)

The prompt sent to the AI includes only the finding context: check name, severity, message, file path, line number, and a short code snippet. Guard never sends your entire codebase or any secrets to the AI. All AI output is treated as suggestions — Guard never applies changes automatically.

Non-Goals
---------

[](#non-goals)

Guard does not:

- Apply patches automatically — all fixes require manual review and `git apply`
- Upload your repository or source code to any external service
- Replace full security audits, penetration testing, or dedicated SAST/DAST tools

Guard is a lightweight first line of defense that catches common Laravel security patterns early in the development cycle.

Recommended CI Setup
--------------------

[](#recommended-ci-setup)

For most teams, this is the golden path:

1. Commit a baseline once:

```
php artisan guard:baseline
git add storage/guard/baseline.json
git commit -m "Add Guard baseline"
```

2. In CI, use:

```
php artisan guard:scan --baseline --changed --base=origin/main --format=github --severity=high
```

This gives you:

- Fast incremental scans (only changed files)
- No legacy noise (baseline suppresses known findings)
- PR annotations only for new issues

CI Integration (GitHub Actions)
-------------------------------

[](#ci-integration-github-actions)

### Basic scan

[](#basic-scan)

```
name: Security Scan
on: [push, pull_request]

jobs:
  guard:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'

      - name: Install dependencies
        run: composer install --no-interaction

      - name: Run Guard scan
        run: php artisan guard:scan --format=github --severity=high
```

### With baseline (recommended for existing projects)

[](#with-baseline-recommended-for-existing-projects)

```
name: Security Scan
on: [push, pull_request]

jobs:
  guard:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'

      - name: Install dependencies
        run: composer install --no-interaction

      - name: Run Guard scan (baseline)
        run: php artisan guard:scan --format=github --severity=high --baseline --strict
```

Commit `storage/guard/baseline.json` to your repository. The scan will only fail on new findings.

### Incremental scan on PRs (fastest)

[](#incremental-scan-on-prs-fastest)

```
name: Security Scan (Incremental)
on:
  pull_request:
    branches: [main]

jobs:
  guard:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'

      - name: Install dependencies
        run: composer install --no-interaction

      - name: Run Guard scan (changed files only)
        run: php artisan guard:scan --changed --base=origin/main --format=github --severity=high
```

Note: `fetch-depth: 0` is required so Guard can compare against the base branch.

### Markdown report as PR comment

[](#markdown-report-as-pr-comment)

```
- name: Run Guard scan
  run: php artisan guard:scan --changed --base=origin/main --format=md --output=guard-report.md --severity=high
  continue-on-error: true

- name: Comment on PR
  if: always()
  uses: marocchino/sticky-pull-request-comment@v2
  with:
    path: guard-report.md
```

License
-------

[](#license)

MIT

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance93

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~34 days

Total

4

Last Release

37d ago

Major Versions

v1.1.0 → v2.0.02026-05-28

### Community

Maintainers

![](https://www.gravatar.com/avatar/27d71933a44feff8905b90da6867281d8bf6b88e4fe2b94f85c4483687f4ad59?d=identicon)[drnasin](/maintainers/drnasin)

---

Top Contributors

[![drnasin](https://avatars.githubusercontent.com/u/3784166?v=4)](https://github.com/drnasin "drnasin (40 commits)")

---

Tags

laravelstatic analysissecurityaiauthorizationciSQL Injectionscannermass-assignment

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/intentphp-guard/health.svg)

```
[![Health](https://phpackages.com/badges/intentphp-guard/health.svg)](https://phpackages.com/packages/intentphp-guard)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[laravel/sail

Docker files for running a basic Laravel application.

1.9k205.7M1.3k](/packages/laravel-sail)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

77022.3M151](/packages/laravel-mcp)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k15](/packages/tempest-framework)[laravel/boost

Laravel Boost accelerates AI-assisted development by providing the essential context and structure that AI needs to generate high-quality, Laravel-specific code.

3.5k21.5M596](/packages/laravel-boost)[laravel/surveyor

Static analysis tool for Laravel applications.

86121.4k13](/packages/laravel-surveyor)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
