PHPackages                             dynamik-dev/cloak-laravel - 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. dynamik-dev/cloak-laravel

ActiveLibrary[Security](/categories/security)

dynamik-dev/cloak-laravel
=========================

Laravel adapter for cloak-php - mask and unmask sensitive data

v0.2.1(5mo ago)12[2 PRs](https://github.com/dynamik-dev/cloak-laravel/pulls)MITPHPPHP ^8.2CI passing

Since Nov 25Pushed 1mo agoCompare

[ Source](https://github.com/dynamik-dev/cloak-laravel)[ Packagist](https://packagist.org/packages/dynamik-dev/cloak-laravel)[ Docs](https://github.com/dynamik-dev/cloak-laravel)[ GitHub Sponsors](https://github.com/:vendor_name)[ RSS](/packages/dynamik-dev-cloak-laravel/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (14)Versions (5)Used By (0)

Cloak for Laravel
=================

[](#cloak-for-laravel)

 [![Cloak for Laravel](cloak-laravel.png)](cloak-laravel.png)

[![Latest Version on Packagist](https://camo.githubusercontent.com/23a9d75ac3930a2c11b3db473761e0c3e0591a4950ca01093d15ddb95607f1e1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f64796e616d696b6465762f636c6f616b2d6c61726176656c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/dynamikdev/cloak-laravel)[![GitHub Tests Action Status](https://camo.githubusercontent.com/1156105df0c312db77de8961ed33b2e132ac2f173d077ccdbe1b391eb2fda640/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f64796e616d696b2d6465762f636c6f616b2d6c61726176656c2f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/dynamik-dev/cloak-laravel/actions?query=workflow%3Arun-tests+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/fd7c99d458500783ede64ccd09c0654cd653168c6b459d3b5c9d571d05146c1b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f64796e616d696b6465762f636c6f616b2d6c61726176656c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/dynamikdev/cloak-laravel)

**Keep PII out of LLMs.** Cloak masks sensitive data before sending text to AI APIs like ChatGPT or Claude, then restores the original data in responses.

Quick Start
-----------

[](#quick-start)

```
// Mask PII before sending to an LLM
$safe = cloak('Contact john@example.com or call 555-123-4567');
// "Contact {{EMAIL_x7k2m9_1}} or call {{PHONE_x7k2m9_1}}"

// Restore the original data
$original = uncloak($safe);
// "Contact john@example.com or call 555-123-4567"
```

Why Cloak?
----------

[](#why-cloak)

When building AI-powered features, user messages often contain sensitive information—emails, phone numbers, SSNs, credit cards. Sending this data to third-party LLM APIs creates privacy and compliance risks.

Cloak solves this by:

1. **Detecting** PII using built-in or custom detectors
2. **Replacing** sensitive data with placeholder tokens
3. **Storing** the mapping temporarily (in-memory or cache)
4. **Restoring** original data when you receive the LLM's response

The LLM never sees the actual PII, but your users get personalized responses.

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

[](#installation)

```
composer require dynamik-dev/cloak-laravel
```

Optionally publish the config file:

```
php artisan vendor:publish --tag="cloak-config"
```

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

[](#configuration)

```
// config/cloak.php
return [
    // false (default): In-memory storage, auto-cleared after request
    // true: Cache storage, persists across requests
    'persist' => env('CLOAK_PERSIST', false),

    // Storage driver class when persist is true
    'storage_driver' => DynamikDev\Cloak\Laravel\CacheStorage::class,

    // Cache store to use (null = default cache)
    'cache_store' => env('CLOAK_CACHE_STORE'),

    // TTL for cached mappings in seconds
    'default_ttl' => env('CLOAK_DEFAULT_TTL', 3600),
];
```

### Encryption at Rest

[](#encryption-at-rest)

This Laravel adapter integrates with cloak-php v0.2.0's encryption system using Laravel's `Crypt` facade. All sensitive data is encrypted before being stored, providing defense in depth—even if memory or cache is compromised, the original PII remains protected.

The encryption is handled through a custom `LaravelEncryptor` that implements cloak-php's `EncryptorInterface`, using Laravel's built-in encryption for seamless integration with your application's `APP_KEY`.

### Persist Mode

[](#persist-mode)

- **`persist: false`** (default) - In-memory storage with encryption. Perfect for single-request flows where you cloak → call LLM → uncloak in one request. Data is automatically garbage collected when the request ends.
- **`persist: true`** - Laravel cache storage with encryption. Use this when you need to uncloak in a different request (e.g., webhook responses, queued jobs). TTL is configurable via `default_ttl`.

Usage
-----

[](#usage)

### Helper Functions

[](#helper-functions)

The simplest way to use Cloak:

```
$masked = cloak($text);
$restored = uncloak($masked);
```

### Facade

[](#facade)

```
use DynamikDev\Cloak\Laravel\Facades\Cloak;

$masked = Cloak::cloak($text);
$restored = Cloak::uncloak($masked);
```

### Dependency Injection

[](#dependency-injection)

```
use DynamikDev\Cloak\Cloak;

class ChatController extends Controller
{
    public function send(Request $request, Cloak $cloak)
    {
        $safe = $cloak->cloak($request->input('message'));
        // ...
    }
}
```

Real-World Example: OpenAI Integration
--------------------------------------

[](#real-world-example-openai-integration)

```
use OpenAI\Laravel\Facades\OpenAI;

public function chat(Request $request)
{
    $userMessage = $request->input('message');
    // "Help me email john.doe@acme.com about invoice #1234.
    //  My number is 555-867-5309 if they need to call back."

    // 1. Cloak PII before sending to OpenAI
    $safeMessage = cloak($userMessage);
    // "Help me email {{EMAIL_a1b2c3_1}} about invoice #1234.
    //  My number is {{PHONE_a1b2c3_1}} if they need to call back."

    // 2. Send to OpenAI - no PII exposed to the API
    $response = OpenAI::chat()->create([
        'model' => 'gpt-4',
        'messages' => [
            ['role' => 'system', 'content' => 'You are a helpful assistant.'],
            ['role' => 'user', 'content' => $safeMessage],
        ],
    ]);

    // 3. Get the response (LLM uses placeholders naturally)
    $aiResponse = $response->choices[0]->message->content;
    // "Here's a draft email for {{EMAIL_a1b2c3_1}}:
    //  Subject: Regarding Invoice #1234..."

    // 4. Restore PII for the user
    $finalResponse = uncloak($aiResponse);
    // "Here's a draft email for john.doe@acme.com:
    //  Subject: Regarding Invoice #1234..."

    return response()->json(['response' => $finalResponse]);
}
```

Built-in Detectors
------------------

[](#built-in-detectors)

Cloak automatically detects:

TypeExamplePlaceholderEmail`john@example.com``{{EMAIL_x1y2z3_1}}`Phone`555-123-4567``{{PHONE_x1y2z3_1}}`SSN`123-45-6789``{{SSN_x1y2z3_1}}`Credit Card`4111-1111-1111-1111``{{CREDIT_CARD_x1y2z3_1}}`By default, all detectors run. To use specific detectors:

```
use DynamikDev\Cloak\Detector;

// Only detect emails and phones
$masked = cloak($text, [
    Detector::email(),
    Detector::phone(),
]);

// Phone detection with region hint (improves accuracy)
$masked = cloak($text, [
    Detector::phone('US'),
]);
```

Custom Detectors
----------------

[](#custom-detectors)

### Pattern Detector (Regex)

[](#pattern-detector-regex)

```
use DynamikDev\Cloak\Detector;

// Detect database connection strings
$masked = cloak($text, [
    Detector::pattern(
        '/mysql:\/\/[^:]+:[^@]+@[^\s]+/',
        'DB_CONNECTION'
    ),
]);

// Detect API keys
$masked = cloak($text, [
    Detector::pattern(
        '/sk-[a-zA-Z0-9]{32,}/',
        'API_KEY'
    ),
]);
```

### Word Detector

[](#word-detector)

```
use DynamikDev\Cloak\Detector;

// Mask specific names or terms (case-insensitive)
$masked = cloak($text, [
    Detector::words(['John Doe', 'Jane Smith', 'Acme Corp'], 'NAME'),
]);
```

### Callback Detector

[](#callback-detector)

For complex detection logic:

```
use DynamikDev\Cloak\Detector;

$masked = cloak($text, [
    Detector::using(function (string $text) {
        // Return array of ['match' => '...', 'type' => '...']
        $matches = [];

        // Example: Find Laravel env variables
        if (preg_match_all('/\bDB_PASSWORD=\S+/', $text, $found)) {
            foreach ($found[0] as $match) {
                $matches[] = ['match' => $match, 'type' => 'ENV_VAR'];
            }
        }

        return $matches;
    }),
]);
```

Middleware Example
------------------

[](#middleware-example)

Auto-cloak sensitive data in request logs:

```
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class LogSafeRequests
{
    public function handle(Request $request, Closure $next)
    {
        // Log request with PII masked
        Log::info('API Request', [
            'path' => $request->path(),
            'body' => cloak(json_encode($request->all())),
        ]);

        return $next($request);
    }
}
```

Testing
-------

[](#testing)

```
composer test
```

Version Compatibility
---------------------

[](#version-compatibility)

This package has been updated to work with **cloak-php v0.2.0**, which includes:

- New builder pattern API for configuring Cloak instances
- Pluggable encryption system via `EncryptorInterface`
- Enhanced lifecycle hooks and filtering capabilities
- Simplified storage interface (TTL handling moved to storage implementations)

### What Changed in v0.2.0

[](#what-changed-in-v020)

**Architecture improvements:**

- Now uses cloak-php's `ArrayStore` for in-memory storage (instead of custom `EncryptedArrayStorage`)
- Implements a `LaravelEncryptor` that integrates with Laravel's `Crypt` facade
- Service provider uses the builder pattern: `Cloak::using($store)->withEncryptor($encryptor)`
- Uses `Cloak::resolveUsing()` to integrate with Laravel's container
- Helper functions now provided by core package (Laravel-specific helpers removed)
- TTL configuration is Laravel-specific and handled within `CacheStorage` constructor

**Container Binding Strategy (Octane-safe):**

- `Cloak` instances use `bind()` - fresh instance on every resolution (prevents state pollution)
- `StoreInterface` uses `singleton()` - shared storage for placeholder mappings
- `EncryptorInterface` uses `singleton()` - stateless encryption service

This architecture prevents issues with filters, callbacks, and other stateful configurations, especially in Laravel Octane environments where state can leak between requests.

**Breaking changes from previous versions:**

- `EncryptedArrayStorage` class has been removed (now uses core `ArrayStore` with `LaravelEncryptor`)
- `StoreInterface::put()` no longer accepts `$ttl` parameter (moved to storage implementation constructor)
- Laravel-specific helper functions removed (now uses core package helpers via resolver)

The package maintains backward compatibility at the API level—all helpers, facades, and configuration options work the same way for end users.

### Advanced Usage: Extending Cloak

[](#advanced-usage-extending-cloak)

The resolver pattern allows developers to customize Cloak behavior through the container:

```
// In your AppServiceProvider
use DynamikDev\Cloak\Cloak;
use DynamikDev\Cloak\Detector;

$this->app->extend(Cloak::class, function ($cloak, $app) {
    return $cloak->withDetectors([
        Detector::email(),
        Detector::phone('US'),
        // Add your custom detectors
    ])->filter(function ($detection) {
        // Filter out test emails
        return !str_ends_with($detection['match'], '@test.local');
    });
});
```

Each call to `cloak()` or `app(Cloak::class)` gets a fresh instance with your customizations, preventing state pollution across requests.

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [DynamikDev](https://github.com/dynamik-dev)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance82

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 75% 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 ~2 days

Total

2

Last Release

171d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/990cfbdeab8ba6fd8c12d682db3e9723e22350bb8b377d91d692927f3e195241?d=identicon)[christopherarter](/maintainers/christopherarter)

---

Top Contributors

[![christopherarter](https://avatars.githubusercontent.com/u/12786153?v=4)](https://github.com/christopherarter "christopherarter (6 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

laravelpiiMaskingSensitive datacloakDynamikDev

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/dynamik-dev-cloak-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/dynamik-dev-cloak-laravel/health.svg)](https://phpackages.com/packages/dynamik-dev-cloak-laravel)
```

###  Alternatives

[spatie/laravel-health

Monitor the health of a Laravel application

85810.0M83](/packages/spatie-laravel-health)[spatie/laravel-ciphersweet

Use ciphersweet in your Laravel project

416718.4k1](/packages/spatie-laravel-ciphersweet)[spatie/laravel-livewire-wizard

Build wizards using Livewire

4061.0M4](/packages/spatie-laravel-livewire-wizard)[clickbar/laravel-magellan

This package provides functionality for working with the postgis extension in Laravel.

423715.4k1](/packages/clickbar-laravel-magellan)[spatie/laravel-prometheus

Export Laravel metrics to Prometheus

2651.3M6](/packages/spatie-laravel-prometheus)[vormkracht10/laravel-mails

Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.

24149.7k](/packages/vormkracht10-laravel-mails)

PHPackages © 2026

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