PHPackages                             laravelsecurityaudit/laravel-ai-egress-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. [Security](/categories/security)
4. /
5. laravelsecurityaudit/laravel-ai-egress-guard

ActiveLibrary[Security](/categories/security)

laravelsecurityaudit/laravel-ai-egress-guard
============================================

Scan, redact, and optionally block outbound requests to AI providers (OpenAI, Anthropic, Gemini, and more) for leaked secrets and PII. Review in an inbox and fail CI before a prompt leaks. SDK-agnostic, at the HTTP layer.

v0.1.0(1mo ago)012↓50%1MITPHPPHP ^8.2CI passing

Since Jun 28Pushed 1mo agoCompare

[ Source](https://github.com/laravelsecurityaudit/laravel-ai-egress-guard)[ Packagist](https://packagist.org/packages/laravelsecurityaudit/laravel-ai-egress-guard)[ Docs](https://github.com/laravelsecurityaudit/laravel-ai-egress-guard)[ RSS](/packages/laravelsecurityaudit-laravel-ai-egress-guard/feed)WikiDiscussions main Synced 2w ago

READMEChangelogDependencies (12)Versions (2)Used By (1)

Laravel AI Egress Guard
=======================

[](#laravel-ai-egress-guard)

Scan every outbound request your Laravel app makes to an AI provider (OpenAI, Anthropic, Gemini, and more) for leaked secrets and PII. Review findings in a built-in inbox, fail your test suite when a prompt would leak, and optionally block an unsafe request before it leaves the app.

Mail Guard answers "is this email safe to send". Egress Guard answers "is this prompt safe to send to a third-party model". It works at the HTTP-client layer, so it is independent of which AI SDK you use.

> This is an independent open-source package. It is not affiliated with, endorsed by, or sponsored by Laravel, Laravel LLC, or any AI provider.

Why this exists
---------------

[](#why-this-exists)

A prompt is built from runtime data: a user record, a support ticket, a row from your database. That data can carry an API key, a card number, an email address, a private key, straight to a third party you do not control. The leak is in the data interpolated at call time, not in the code, so static review cannot see it. Egress Guard runs on the actual outbound request body, so it catches what review cannot.

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

[](#requirements)

- PHP 8.2+
- Laravel 12 or 13

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

[](#installation)

```
composer require laravelsecurityaudit/laravel-ai-egress-guard
php artisan migrate
```

The service provider is auto-discovered. Capture and the inbox are enabled outside production by default. It depends on `laravelsecurityaudit/laravel-secret-scanner` for the detection engine.

How it works
------------

[](#how-it-works)

Egress Guard registers a global HTTP-client middleware. For every outbound request to a host in `egress-guard.providers`, it builds a scan context from the request body, runs the rule set, stores the request and its findings (with high-confidence secrets redacted and the provider key stripped from the stored headers), and, when guard mode is on, can stop the request.

Requests to any other host are ignored on a fast path.

Coverage: Prism, the Http facade, and other SDKs
------------------------------------------------

[](#coverage-prism-the-http-facade-and-other-sdks)

The global hook covers every request made through Laravel's `Http` client. Prism is built on Laravel's HTTP client, so Prism calls are covered automatically, as are the official `laravel/ai` SDK and anything using the `Http` facade.

A client that ships its own Guzzle stack (for example `openai-php`) is not seen by the global hook. Attach the guard to those clients directly:

```
use LaravelSecurityAudit\EgressGuard\Support\EgressGuard;

$client = new \GuzzleHttp\Client(['handler' => EgressGuard::stack()]);
// or push EgressGuard::handler() onto an existing handler stack.
```

If you have disabled the global hook and want to guard a single Prism call, pass the guard through Prism's `withClientOptions()`:

```
use LaravelSecurityAudit\EgressGuard\Support\EgressGuard;

// ...->withClientOptions(EgressGuard::clientOptions())
```

Provider-aware prompt parsing
-----------------------------

[](#provider-aware-prompt-parsing)

For OpenAI, Anthropic, and Gemini request shapes, Egress Guard extracts the model and a readable prompt (`messages[].content`, Anthropic `system`, Gemini `contents[].parts[].text`) and stores it alongside the raw body for the inbox. By default the full raw body is scanned (most thorough). Set `scan.target` to `prompt` (or `EGRESS_GUARD_SCAN_TARGET=prompt`) to scan only the extracted message text when the raw JSON is too noisy.

The inbox
---------

[](#the-inbox)

In an unguarded environment, open `/egress-guard`. Each captured request shows its provider, model, a risk badge, and the security findings, with the body redacted. The inbox can contain sensitive prompt data, so it is closed by default unless explicitly opened:

1. If `egress-guard.gate` is set, that gate must pass for every request.
2. If no gate is set, the inbox is served only in `egress-guard.unguarded_environments` (default `['local']`). Anywhere else it returns a 403.

```
// config/egress-guard.php
'middleware' => ['web', 'auth'],
'gate' => 'viewEgressGuard',
```

Failing tests when a prompt leaks
---------------------------------

[](#failing-tests-when-a-prompt-leaks)

```
use LaravelSecurityAudit\EgressGuard\Support\EgressGuard;

public function test_the_summary_prompt_leaks_nothing(): void
{
    $this->generateSummaryFor($user); // makes the AI call

    EgressGuard::assertNoCriticalFindings();
}
```

Also available: `assertNoLeaks()`, `assertFlagged($ruleId)`, and `assertNotFlagged($ruleId)`.

Failing CI with SARIF
---------------------

[](#failing-ci-with-sarif)

```
php artisan test
php artisan egress-guard:scan --min-severity=critical --format=sarif --output=egress-guard.sarif
```

`egress-guard:scan` exits non-zero when any finding meets the threshold. Formats are `table`, `json`, and `sarif`. SARIF results point at the calling route action when known, otherwise at a synthetic `egress-guard://request/{id}` location.

Guard mode
----------

[](#guard-mode)

Guard mode blocks a request when a finding meets the configured threshold. It is off by default and is the part you opt into, often in production.

```
EGRESS_GUARD_BLOCK=true
```

Defaults are conservative: it blocks only `critical` findings at `high` confidence, and `fail_open` is true so a scanner error never silently breaks a real AI call. A blocked request throws `EgressGuardBlocked`. Bypass a known-safe call with the `X-Egress-Guard-Bypass` header or the `guard.allow_source` allowlist of route actions. Every block fires an `EgressBlocked` event and a log warning with the rule ids, never the secret.

Residency
---------

[](#residency)

Egress Guard can enforce a data-residency policy. Declare the regions you allow and the region each provider actually processes in, then turn enforcement on:

```
// config/egress-guard.php
'residency' => [
    'enabled' => true,
    'allowed_regions' => ['EU'],
    'regions' => ['openai' => 'EU', 'anthropic' => 'US'],
],
```

A request to a provider whose region is not allowed (here Anthropic, US) is blocked with `EgressGuardBlocked`, exactly like a secret leak, and fires a `ResidencyViolation` event. With `enabled` off, the violation still fires the event (and `laravel-ai-ledger` records it), but the request is not blocked. Set `block_unknown` to also block a provider whose region you have not declared.

Rules
-----

[](#rules)

Rule idSeverityConfidenceSource`secrets.private_key`criticalhighsecret-scanner`secrets.stripe_key`criticalhighsecret-scanner`secrets.api_key`criticalhighegress-guard`secrets.aws_access_key`criticalhighegress-guard`secrets.bearer_token`warningmediumegress-guard`pii.credit_card`criticalhighsecret-scanner`pii.email`warningmediumegress-guard`pii.phone`warninglowegress-guardToggle rules, override severities, and suppress findings in `config/egress-guard.php`. Add your own by implementing `LaravelSecurityAudit\SecretScanner\Scanning\Contracts\Rule`.

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

[](#configuration)

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

```
EGRESS_GUARD_ENABLED=true
EGRESS_GUARD_PATH=egress-guard
EGRESS_GUARD_GATE=viewEgressGuard
EGRESS_GUARD_RETENTION_DAYS=7
EGRESS_GUARD_REDACT=true
EGRESS_GUARD_BLOCK=false
```

Captured requests older than `EGRESS_GUARD_RETENTION_DAYS` are removed by the scheduled `model:prune` command. Set it to 0 to disable.

Testing
-------

[](#testing)

```
composer test
composer analyse
```

The Laravel Security Audit family
---------------------------------

[](#the-laravel-security-audit-family)

One detection engine, guarding every place data leaves your app.

PackageWhat it guards[laravel-secret-scanner](https://packagist.org/packages/laravelsecurityaudit/laravel-secret-scanner)Shared secret and PII detection engine (the core)[laravel-mail-guard](https://packagist.org/packages/laravelsecurityaudit/laravel-mail-guard)Outgoing Laravel mail**laravel-ai-egress-guard** (this package)Outbound AI provider traffic (OpenAI, Anthropic, Gemini)[laravel-ai-lint](https://packagist.org/packages/laravelsecurityaudit/laravel-ai-lint)Static analysis: leaked AI keys and unsafe AI wiring[laravel-ai-circuit-breaker](https://packagist.org/packages/laravelsecurityaudit/laravel-ai-circuit-breaker)Runaway AI loops and spend[laravel-ai-ledger](https://packagist.org/packages/laravelsecurityaudit/laravel-ai-ledger)GDPR Article 30 processing ledger for AI trafficLicense
-------

[](#license)

The MIT License (MIT). See [LICENSE](LICENSE).

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance90

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

 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

Unknown

Total

1

Last Release

45d ago

### Community

Maintainers

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

---

Top Contributors

[![workaandrey](https://avatars.githubusercontent.com/u/1831403?v=4)](https://github.com/workaandrey "workaandrey (3 commits)")

---

Tags

laravelsecurityaiopenaisecretsllmanthropicpiiegress

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/laravelsecurityaudit-laravel-ai-egress-guard/health.svg)

```
[![Health](https://phpackages.com/badges/laravelsecurityaudit-laravel-ai-egress-guard/health.svg)](https://phpackages.com/packages/laravelsecurityaudit-laravel-ai-egress-guard)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k161.4k2](/packages/mike-bronner-laravel-model-caching)[aedart/athenaeum

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

255.2k](/packages/aedart-athenaeum)[spatie/laravel-export

Create a static site bundle from a Laravel app

679153.2k7](/packages/spatie-laravel-export)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5226.7k](/packages/simplestats-io-laravel-client)

PHPackages © 2026

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