PHPackages                             andreapollastri/checkpoint - 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. [DevOps &amp; Deployment](/categories/devops)
4. /
5. andreapollastri/checkpoint

ActiveLibrary[DevOps &amp; Deployment](/categories/devops)

andreapollastri/checkpoint
==========================

Laravel security scanner — checks CVEs, hardcoded secrets, SQL injection, XSS and more via a single Artisan command.

1.1.1(1mo ago)7014.1k↑2438.9%11MITPHPPHP ^8.1

Since Apr 27Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/andreapollastri/checkpoint)[ Packagist](https://packagist.org/packages/andreapollastri/checkpoint)[ RSS](/packages/andreapollastri-checkpoint/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (10)Dependencies (12)Versions (14)Used By (1)

Checkpoint
==========

[](#checkpoint)

> A Laravel security scanner that audits your application for common vulnerabilities — from known CVEs to hardcoded secrets — via a single Artisan command.

```
php artisan checkpoint:scan

```

---

What it checks
--------------

[](#what-it-checks)

\#CheckSeverity1**Composer CVE Audit** — runs `composer audit` and reports known advisories`FAIL`2**NPM CVE Audit** — runs `npm audit` and flags critical/high vulnerabilities`FAIL` / `WARN`3**Environment Configuration** — `APP_DEBUG`, `APP_KEY`, `APP_URL`, `SESSION_SECURE_COOKIE``WARN`4**`.gitignore` Sensitive Files** — ensures `.env`, `*.key`, `*.pem` are excluded; detects if `.env` is tracked by git`FAIL`5**File Permissions** — flags world-readable `.env` or world-writable `storage/``WARN`6**Hardcoded Secrets** — scans PHP/JS files for API keys, Stripe tokens, AWS keys, GitHub PATs, PEM headers`FAIL`7**SQL Injection Risks** — detects raw queries with variable interpolation (`DB::select("… $var")`, `->whereRaw(…)`)`FAIL`8**Mass Assignment Vulnerabilities** — finds `$guarded = []`, `Model::unguard()`, or models with no fillable/guarded definition`WARN`9**XSS (Cross-Site Scripting) Risks** — flags unescaped `{!! $var !!}` in Blade views and raw `echo` of request input`WARN`10**CSRF Protection** — detects forms with `POST`/`PUT`/`PATCH`/`DELETE` missing `@csrf`, and checks middleware is present`FAIL`11**Open Redirect Risks** — spots `redirect($request->…)` or `header('Location: ' . $var)` with unvalidated input`WARN`12**Command Injection Risks** — finds `exec`, `shell_exec`, `system`, `passthru`, `proc_open` called with unescaped variables`FAIL`13**Insecure Deserialization** — detects `unserialize($userInput)` and the classic `unserialize(base64_decode(…))` exploit chain`FAIL`14**Debug Functions in Production Code** — finds `var_dump`, `dd`, `dump`, `ray` left outside of test files`WARN`15**Sensitive Data Exposure** — flags `display_errors = 1`, logging of passwords/tokens, and Telescope always-on config`WARN`16**SSRF Risks** — detects `Http::get($request->…)`, Guzzle/cURL/`file_get_contents` called with user-controlled URLs`FAIL`17**TLS Certificate Verification** — flags `withoutVerifying()`, `'verify' => false`, `CURLOPT_SSL_VERIFYPEER => false``FAIL`18**CORS Configuration** — flags `allowed_origins => ['*']` combined with `supports_credentials => true` and other loose configs`FAIL` / `WARN`19**Package Freshness (Supply Chain)** — fails the scan if any Composer package was released within the last N days (default 3); whitelist via config`FAIL`20**Supply Chain Tooling** — when `package.json` is present, warns if no npm install-time guard (Safe-Chain, Socket CLI) is on PATH`WARN`21**Path Traversal Risks** — detects `Storage::get($request->…)`, `file_get_contents`/`include`/`require` with user-controlled paths`FAIL`22**Weak Cryptography** — flags `mcrypt_*`, ECB mode, DES/3DES/RC4, and `md5`/`sha1` used near password/token/HMAC keywords`FAIL` / `WARN`23**Insecure RNG** — detects `rand`/`mt_rand`/`uniqid` used in security contexts (tokens, CSRF, password reset, OTP)`FAIL`24**Session &amp; Cookie Security** — audits `config/session.php` for `http_only=false`, `same_site=null/none`, `secure=false`, `encrypt=false``WARN`25**EOL Versions** — flags Composer-locked Laravel and the running PHP when they are past or approaching upstream security cutoff`FAIL` / `WARN`26**Suspicious Vendor Autoload** — flags packages under `vendor/` that register PHP via `autoload.files` outside a baked-in whitelist (the mechanism abused by the May 2026 Laravel-Lang supply-chain attack)`WARN`---

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

[](#requirements)

- **PHP** `^8.1` is the package floor. Newer Laravel versions may require a higher PHP, so your effective minimum is whatever your Laravel major demands.
- **Laravel** `8`–`13` (same major as `illuminate/*` 8.x–13.x used by your app)

---

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

[](#installation)

```
composer require --dev andreapollastri/checkpoint
```

The package auto-discovers itself via Laravel's package discovery — no manual registration needed.

---

Recommended companion tools
---------------------------

[](#recommended-companion-tools)

Checkpoint is a static scanner — it inspects your codebase but doesn't intercept package installs. To harden the npm install path against the next event-stream/ua-parser-js/chalk-style supply-chain attack, pair Checkpoint with **defense in depth**: run installs inside containers and add a runtime guard on the host when you must install locally.

### Docker (recommended)

[](#docker-recommended)

Run `composer install`, `npm install`, and `php artisan checkpoint:scan` **inside a container**, not directly on your laptop or server shell. Supply-chain malware often executes during a package's post-install script — if that runs on your host, it has access to your SSH keys, browser cookies, and filesystem. A disposable dev container limits blast radius to an isolated filesystem that you can throw away.

Typical workflow:

```
docker compose up -d
docker compose exec app composer install
docker compose exec app npm install
docker compose exec app php artisan checkpoint:scan
```

Use whatever Docker setup fits your project — Docker Compose, a devcontainer, or a CI image such as `composer:2` with Node in the same job. The goal is the same: **never let untrusted install scripts run on bare metal**; treat the host as a control plane only.

> Checkpoint's CI scaffolds ([GitHub Actions](#github-actions), [GitLab CI](#gitlab-ci)) already run the scan inside ephemeral containers. Mirror that pattern locally.

### Safe-Chain (recommended)

[](#safe-chain-recommended)

[Safe-Chain](https://www.npmjs.com/package/@aikidosec/safe-chain) by Aikido is a free shell shim that blocks known-malicious npm packages **before** their install scripts run. Install it once, globally:

```
npm install -g @aikidosec/safe-chain
safe-chain setup
```

When you **do** run npm on the host (CI runners, one-off scripts), Safe-Chain blocks known-malicious packages **before** their install scripts run. Checkpoint's **Supply Chain Tooling** check verifies whether Safe-Chain (or an equivalent like Socket CLI) is on your `PATH` and emits a `WARN` if no protection is present.

> Why Checkpoint doesn't install it for you: Safe-Chain works as a global shell shim, not a project dependency. A `composer require` should never invoke another ecosystem's package manager (and can't reliably do so on hosts without Node). Installing it explicitly keeps the install path auditable. Prefer Docker for day-to-day installs; keep Safe-Chain as a safety net where containers aren't practical.

---

Usage
-----

[](#usage)

### Run all checks

[](#run-all-checks)

```
php artisan checkpoint:scan
```

### Run only specific checks

[](#run-only-specific-checks)

```
php artisan checkpoint:scan --only="SQL Injection Risks,CSRF Protection"
```

### Skip specific checks

[](#skip-specific-checks)

```
php artisan checkpoint:scan --skip="NPM CVE Audit,Debug Functions in Production Code"
```

### JSON output (for CI/CD pipelines)

[](#json-output-for-cicd-pipelines)

```
php artisan checkpoint:scan --json
```

The command exits with code `1` if any check returns `FAIL`, making it suitable as a pipeline gate.

---

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

[](#configuration)

Checkpoint works out of the box with sensible defaults. Publish the config file when you need to toggle individual checks or tune the freshness gate:

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

This creates `config/checkpoint.php` with two sections:

### Enabling / disabling checks

[](#enabling--disabling-checks)

Every default check is listed and enabled. Set any entry to `false` to exclude it from the scan:

```
'checks' => [
    Checks\ComposerAuditCheck::class      => true,
    Checks\NpmAuditCheck::class           => false, // skip npm audit on a PHP-only project
    Checks\EnvironmentCheck::class        => true,
    // …
    Checks\PackageFreshnessCheck::class   => true,
    Checks\SupplyChainToolingCheck::class => true,
],
```

> Checks not listed in the map fall back to **enabled**. When you upgrade Checkpoint and new checks are added, you keep the protection without re-publishing the config — re-publish only when you want to see the full updated list.

### Package Freshness tuning

[](#package-freshness-tuning)

```
'package_freshness' => [
    'minimum_age_days' => 3,
    'whitelist' => [
        'andreapollastri/checkpoint', // bundled — see note below
        // 'laravel/framework',
        // 'symfony/console',
    ],
],
```

- `minimum_age_days` — packages released more recently than this fail the scan. Default `3`. **Set to `0` to bypass the freshness gate entirely** without removing the check from the scanner.
- `whitelist` — fully-qualified package names (`vendor/package`) exempt from the freshness check. Use sparingly and ideally with an inline comment explaining why each entry is allowed.

> Checkpoint ships with `andreapollastri/checkpoint` already whitelisted by default — a fresh release of the scanner itself should never block its own user's deploy. Remove the entry if you want to gate even Checkpoint upgrades through the freshness window.

### Suppressing individual findings

[](#suppressing-individual-findings)

Every `WARN` or `FAIL` finding is shown with a stable 12-character hash:

```
FAIL  Hardcoded Secrets
      3 potential hardcoded secret(s) found.
        ✗ app/Services/PaymentService.php:14 — 'api_key' => 'sk_live_…' [a1b2c3d4e5f6]
        ✗ config/services.php:8 — $secret = 'super…'                    [9f8e7d6c5b4a]

```

To silence one — false positive, accepted legacy code, internal test fixture — copy the bracketed hash into `config/checkpoint.php`:

```
'suppressed' => [
    'a1b2c3d4e5f6',
    '9f8e7d6c5b4a',
],
```

On the next run those findings are filtered out. If every finding of a given check ends up suppressed, the check is downgraded to `PASS` with an explicit `"All N finding(s) suppressed via config."` message — so the suppression is visible in the output, not silently ignored.

The hash is content-stable: refactors that only shift line numbers within the same file will **not** invalidate the suppression. The hash *does* change if you alter the file path or the finding content itself, which is the intended safety net.

> The `--only` / `--skip` CLI flags still work and override the config for the current run, which is handy for ad-hoc scans without editing the config.

### Excluding folders from file scans

[](#excluding-folders-from-file-scans)

File-based checks (Hardcoded Secrets, SQL Injection, XSS, and others) skip built-in paths such as `vendor/`, `node_modules/`, and `storage/`. Add your own paths when you have mounted data directories or other folders that are not part of your application source:

```
'exclude_paths' => [
    'storage/app/mounted-data',
    'data/external',
],
```

Paths are relative to the project root. Leading and trailing slashes are optional. Unreadable directories are skipped automatically so permission errors on mounted volumes do not abort the scan.

---

Example output
--------------

[](#example-output)

```
  ██████╗██╗  ██╗███████╗ ██████╗██╗  ██╗██████╗  ██████╗ ██╗███╗  ██╗████████╗
 ██╔════╝██║  ██║██╔════╝██╔════╝██║ ██╔╝██╔══██╗██╔═══██╗██║████╗ ██║╚══██╔══╝
 ██║     ███████║█████╗  ██║     █████╔╝ ██████╔╝██║   ██║██║██╔██╗██║   ██║
 ██║     ██╔══██║██╔══╝  ██║     ██╔═██╗ ██╔═══╝ ██║   ██║██║██║╚████║   ██║
  ╚█████╗██║  ██║███████╗ ╚█████╗██║  ██╗██║      ╚█████╔╝██║██║ ╚███║   ██║
   ╚════╝╚═╝  ╚═╝╚══════╝  ╚════╝╚═╝  ╚═╝╚═╝       ╚════╝ ╚═╝╚═╝  ╚══╝   ╚═╝

  Laravel Security Scanner — andreapollastri/checkpoint
  Scanning: /var/www/my-app

  PASS  Composer CVE Audit
        No known CVEs in Composer dependencies.

  FAIL  Hardcoded Secrets
        3 potential hardcoded secret(s) found.
          ✗ app/Services/PaymentService.php:14 — 'api_key' => 'sk_live_abc123…' [a1b2c3d4e5f6]
          ✗ config/services.php:8 — $secret = 'supersecretvalue'             [9f8e7d6c5b4a]
          ✗ app/Http/Controllers/WebhookController.php:31 — 'api_key' => 'ghp_…' [3e2d1c0b9a8f]

  FAIL  Path Traversal Risks
        1 potential path traversal risk(s) found.
          ✗ app/Http/Controllers/DownloadController.php:24 — Storage::get($request->path) [7b6a5f4e3d2c]

  WARN  Environment Configuration
        3 environment issue(s) found.
          ⚑ APP_DEBUG is true — full stack traces will be exposed to end users. [5c4b3a2d1e0f]
          ⚑ SESSION_SECURE_COOKIE is not enabled.                               [1a2b3c4d5e6f]
          ⚑ APP_URL is set to "http://localhost" — update it for production.    [6e5d4c3b2a1f]

  ─────────────────────────────────────────────────────────
  Summary  19 passed  4 warning(s)  2 failed  (25 checks total)

  Scan result: FAIL — fix the issues above before deploying.

```

---

Extending with custom checks
----------------------------

[](#extending-with-custom-checks)

Create a class that extends `AbstractCheck` and return a `CheckResult`:

```
use Checkpoint\Checks\AbstractCheck;
use Checkpoint\Checks\CheckResult;

class MyCustomCheck extends AbstractCheck
{
    public function name(): string
    {
        return 'My Custom Check';
    }

    public function run(): CheckResult
    {
        // your logic here
        return CheckResult::pass('Everything looks good.');
        // or: CheckResult::warn('Something to review.', ['detail one', 'detail two']);
        // or: CheckResult::fail('Critical issue found.', ['detail']);
    }
}
```

Then register it by building a `Scanner` manually instead of using the default:

```
use Checkpoint\Scanner;

$scanner = Scanner::withDefaultChecks(base_path())
    ->add(new MyCustomCheck());
```

---

CI/CD integration
-----------------

[](#cicd-integration)

Checkpoint can scaffold a ready-to-use pipeline for either provider in one command.

### GitHub Actions

[](#github-actions)

```
php artisan checkpoint:github
```

Creates `.github/workflows/checkpoint.yml` — triggers on push to `main`/`master` and on every pull request. Uses `actions/checkout@v4`, `shivammathur/setup-php@v2` (PHP 8.2), Composer cache, and runs `php artisan checkpoint:scan`. Pass `--force` to overwrite an existing file.

### GitLab CI

[](#gitlab-ci)

```
php artisan checkpoint:gitlab
```

Creates `.gitlab-ci.yml` — runs on merge requests and default-branch pushes using the `composer:2` image with a Composer cache. If you already have a `.gitlab-ci.yml`, the command refuses to overwrite and prints the snippet to stdout so you can paste it into your existing pipeline. Use `--force` to overwrite.

### Custom usage

[](#custom-usage)

If you prefer to wire Checkpoint into a pipeline you already maintain, just call:

```
- name: Security audit
  run: php artisan checkpoint:scan --json | tee checkpoint-report.json
```

### Composer hooks

[](#composer-hooks)

Run Checkpoint automatically after every `composer install` / `composer update`:

```
php artisan checkpoint:install-hooks
```

This appends `@php artisan checkpoint:scan` to `scripts.post-update-cmd` and `scripts.post-install-cmd` in your `composer.json`. The command:

- Confirms interactively before touching `composer.json` (skip the prompt with `--no-interaction` for CI).
- Is idempotent: re-running on an already-installed setup is a no-op.
- Preserves any existing hooks (append-only); does **not** overwrite scripts owned by other tools.
- Supports `--remove` to cleanly uninstall and `--force` to replace stale Checkpoint entries.

> **Why only `post-*`, not `pre-*`?** Composer's `pre-update-cmd` fires *before* dependencies are resolved, so the scanner would only see the codebase pre-update — useless against a malicious package that's about to be installed. And on a fresh clone there is no `vendor/`, so `php artisan` does not exist yet and `pre-install-cmd` would crash. Real-time interception of malicious installs is the job of [Docker](#docker-recommended) (preferred) and [Safe-Chain](#safe-chain-recommended) on the host.

### Exit codes

[](#exit-codes)

CodeMeaning`0`All checks passed (or warnings only)`1`At least one check returned `FAIL`---

Architecture
------------

[](#architecture)

```
src/
├── CheckpointServiceProvider.php   # auto-registers the command
├── Scanner.php                     # orchestrates all checks
├── Commands/
│   ├── ScanCommand.php             # php artisan checkpoint:scan
│   ├── GithubPipelineCommand.php   # php artisan checkpoint:github
│   ├── GitlabPipelineCommand.php   # php artisan checkpoint:gitlab
│   └── InstallHooksCommand.php     # php artisan checkpoint:install-hooks
└── Checks/
    ├── AbstractCheck.php           # base class
    ├── CheckResult.php             # pass / warn / fail value object
    ├── ComposerAuditCheck.php
    ├── NpmAuditCheck.php
    ├── EnvironmentCheck.php
    ├── GitIgnoreCheck.php
    ├── FilePermissionsCheck.php
    ├── HardcodedSecretsCheck.php
    ├── SqlInjectionCheck.php
    ├── MassAssignmentCheck.php
    ├── XssCheck.php
    ├── CsrfCheck.php
    ├── OpenRedirectCheck.php
    ├── CommandInjectionCheck.php
    ├── InsecureDeserializationCheck.php
    ├── DebugFunctionsCheck.php
    ├── SensitiveExposureCheck.php
    ├── SsrfCheck.php
    ├── TlsVerificationCheck.php
    ├── CorsConfigCheck.php
    ├── PackageFreshnessCheck.php
    ├── SuspiciousVendorAutoloadCheck.php
    ├── SupplyChainToolingCheck.php
    ├── PathTraversalCheck.php
    ├── WeakCryptographyCheck.php
    ├── InsecureRngCheck.php
    ├── SessionSecurityCheck.php
    └── EolVersionCheck.php

```

---

License
-------

[](#license)

MIT — [Andrea Pollastri](https://andreapollastri.net)

###  Health Score

52

—

FairBetter than 96% of packages

Maintenance90

Actively maintained with recent releases

Popularity41

Moderate usage in the ecosystem

Community12

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 85.2% 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 ~3 days

Total

13

Last Release

47d ago

PHP version history (2 changes)1.0.0PHP ^8.2

1.0.1PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/d5a4aca6f4b1579cf2e9094c907ae2a9587fab913af88535fdd2a11661443e4b?d=identicon)[andreapollastri](/maintainers/andreapollastri)

---

Top Contributors

[![andreapollastri](https://avatars.githubusercontent.com/u/18210420?v=4)](https://github.com/andreapollastri "andreapollastri (23 commits)")[![danielebarbaro](https://avatars.githubusercontent.com/u/4376886?v=4)](https://github.com/danielebarbaro "danielebarbaro (4 commits)")

---

Tags

automationcomposercybersecuritydeploymentlaravelnpmpipelinesecurity-auditsecurity-automationsecurity-toolssupply-chain-security

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/andreapollastri-checkpoint/health.svg)

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

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M246](/packages/laravel-ai)[tallstackui/tallstackui

TallStackUI is a powerful suite of Blade components that elevate your workflow of Livewire applications.

728176.2k14](/packages/tallstackui-tallstackui)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k96.5k1](/packages/mike-bronner-laravel-model-caching)[spatie/laravel-export

Create a static site bundle from a Laravel app

674146.0k6](/packages/spatie-laravel-export)[iazaran/smart-cache

Smart Cache is a caching optimization package designed to enhance the way your Laravel application handles data caching. It intelligently manages large data sets by compressing, chunking, or applying other optimization strategies to keep your application performant and efficient.

21111.6k](/packages/iazaran-smart-cache)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

255.2k](/packages/aedart-athenaeum)

PHPackages © 2026

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