PHPackages                             kirschbaum-development/redactor - 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. kirschbaum-development/redactor

ActiveLibrary[Security](/categories/security)

kirschbaum-development/redactor
===============================

Sensitive data redactor for Laravel with entropy detection, key policies, and pipeline support.

v0.1.0(1y ago)31.7k↓91.1%2[3 PRs](https://github.com/kirschbaum-development/redactor/pulls)1MITPHPPHP ^8.3|^8.4CI passing

Since Jun 19Pushed 6mo ago1 watchersCompare

[ Source](https://github.com/kirschbaum-development/redactor)[ Packagist](https://packagist.org/packages/kirschbaum-development/redactor)[ RSS](/packages/kirschbaum-development-redactor/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (8)Versions (5)Used By (1)

Kirschbaum Redactor
===================

[](#kirschbaum-redactor)

[![Laravel Supported Versions](https://camo.githubusercontent.com/4b685234c18c2a323630d28899a6df0f78314186029222a4483f21c9c9d9a506/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d31302e782f31312e782f31322e782d677265656e2e737667)](https://camo.githubusercontent.com/4b685234c18c2a323630d28899a6df0f78314186029222a4483f21c9c9d9a506/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d31302e782f31312e782f31322e782d677265656e2e737667)[![MIT Licensed](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![Latest Version on Packagist](https://camo.githubusercontent.com/ad6d9db6094e2d1b27d79e1903a62c9052a791298f5f1f6b4d728508d8329b0c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b69727363686261756d2d646576656c6f706d656e742f7265646163746f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/kirschbaum-development/redactor)[![Application Testing](https://github.com/kirschbaum-development/redactor/actions/workflows/php-tests.yml/badge.svg)](https://github.com/kirschbaum-development/redactor/actions/workflows/php-tests.yml/badge.svg)[![Static Analysis](https://github.com/kirschbaum-development/redactor/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/kirschbaum-development/redactor/actions/workflows/static-analysis.yml/badge.svg)[![Code Style](https://github.com/kirschbaum-development/redactor/actions/workflows/style-check.yml/badge.svg)](https://github.com/kirschbaum-development/redactor/actions/workflows/style-check.yml/badge.svg)

Automatically redact sensitive data from arrays, objects, and strings before logging or exporting. Features a class-based strategy system with profile-based configurations, Shannon entropy detection.

> This package is in active development and its API can change abruptly without any notice. Please reach out if you plan to use it in a production environment.

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

[](#quick-start)

```
composer require kirschbaum-development/redactor
php artisan vendor:publish --tag=redactor-config
```

The package automatically registers the service provider and facade. Use it directly:

```
use Kirschbaum\Redactor\Facades\Redactor;

// Basic usage
$data = [
    'user_id' => 123,
    'password' => 'secret123',
    'api_key' => 'sk-1234567890abcdef1234567890abcdef12345678',
    'email' => 'user@example.com'
];

$redacted = Redactor::redact($data);
// Result:
// [
//     'user_id' => 123,                    // Safe key - preserved
//     'password' => '[REDACTED]',          // Blocked key - redacted
//     'api_key' => '[REDACTED]',           // High entropy - redacted
//     'email' => '[REDACTED]',             // Email pattern - redacted
//     '_redacted' => true                  // Metadata added
// ]
```

Core Concepts
-------------

[](#core-concepts)

### Redaction Strategies

[](#redaction-strategies)

The package uses a class-based configuration:

1. **SafeKeysStrategy** - Preserves safe keys like `id`, `user_id`
2. **BlockedKeysStrategy** - Always redacts blocked keys like `password`, `secret`
3. **LargeObjectStrategy** - Redacts objects/arrays exceeding size limits
4. **LargeStringStrategy** - Redacts strings exceeding length limits
5. **RegexPatternsStrategy** - Custom regex patterns for emails, credit cards, etc.
6. **ShannonEntropyStrategy** - Detects high-entropy strings (API keys, tokens)

### Profiles

[](#profiles)

Profiles provide different redaction configurations for different contexts:

```
// Use built-in profiles
$logData = Redactor::redact($data, 'default');       // Balanced redaction
$auditData = Redactor::redact($data, 'strict');      // Aggressive redaction
$debugData = Redactor::redact($data, 'performance'); // Minimal redaction for speed
```

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

[](#configuration)

The config file (`config/redactor.php`) uses a class-based approach:

```
return [
    'default_profile' => 'default',

    'profiles' => [
        'default' => [
            'enabled' => true,

            // Strategies executed in array order (top-to-bottom priority)
            'strategies' => [
                \Kirschbaum\Redactor\Strategies\SafeKeysStrategy::class,
                \Kirschbaum\Redactor\Strategies\BlockedKeysStrategy::class,
                \Kirschbaum\Redactor\Strategies\LargeObjectStrategy::class,
                \Kirschbaum\Redactor\Strategies\LargeStringStrategy::class,
                \Kirschbaum\Redactor\Strategies\RegexPatternsStrategy::class,
                \Kirschbaum\Redactor\Strategies\ShannonEntropyStrategy::class,
            ],

            'safe_keys' => ['id', 'user_id', 'uuid', 'created_at', 'updated_at'],
            'blocked_keys' => ['password', 'secret', 'token', 'api_key', 'authorization'],
            'patterns' => [
                'email' => '/[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+/',
                'credit_card' => '/\b(?:\d[ -]*?){13,16}\b/',
                'ssn' => '/\b\d{3}-?\d{2}-?\d{4}\b/',
                'phone_simple' => '/\b\d{3}[.-]?\d{3}[.-]?\d{4}\b/',
                'url_with_auth' => '/https?:\/\/[^:\/\s]+:[^@\/\s]+@[^\s]+/',
            ],
            'replacement' => '[REDACTED]',
            'mark_redacted' => true,
            'track_redacted_keys' => false,
            'non_redactable_object_behavior' => 'preserve', // 'preserve', 'remove', 'redact', 'empty_array'
            'max_value_length' => 5000,
            'redact_large_objects' => true,
            'max_object_size' => 100,

            'shannon_entropy' => [
                'enabled' => true,
                'threshold' => 4.8,  // Higher = more selective
                'min_length' => 25,  // Only analyze strings this long or longer
                'exclusion_patterns' => [
                    '/^https?:\/\//', // URLs
                    '/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', // UUIDs
                    '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/',      // IP addresses
                    '/^[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}$/i', // MAC addresses
                ],
            ],
        ],
    ],
];
```

Wildcard Patterns
-----------------

[](#wildcard-patterns)

The `BlockedKeysStrategy` and `SafeKeysStrategy` support powerful wildcard patterns using the `*` character. This allows you to match multiple key variations without listing each one explicitly.

### Basic Wildcard Usage

[](#basic-wildcard-usage)

```
// config/redactor.php
'profiles' => [
    'wildcard_example' => [
        'enabled' => true,
        'strategies' => [
            \Kirschbaum\Redactor\Strategies\BlockedKeysStrategy::class,
        ],
        'blocked_keys' => [
            '*token*',        // Matches any key containing "token"
            '*key*',          // Matches any key containing "key"
            'password',       // Exact match (no wildcards)
            'user_*_data',    // Matches keys like "user_profile_data", "user_settings_data"
        ],
        // ... other config
    ],
];

// Usage example
$data = [
    'user_id' => 123,
    'api_token' => 'secret123',           // Matched by *token*
    'access_token' => 'abc123',           // Matched by *token*
    'my_custom_token' => 'xyz789',        // Matched by *token*
    'user_api_key' => 'key123',           // Matched by *key*
    'private_key_data' => 'private',      // Matched by *key*
    'password' => 'secret',               // Matched by exact "password"
    'user_profile_data' => 'profile',     // Matched by user_*_data
    'user_settings_data' => 'settings',   // Matched by user_*_data
    'normal_field' => 'safe_value',       // Not matched - preserved
];

$redacted = Redactor::redact($data, 'wildcard_example');
```

### Wildcard Pattern Types

[](#wildcard-pattern-types)

#### Contains Pattern (`*word*`)

[](#contains-pattern-word)

Matches any key that contains the specified word anywhere:

```
'blocked_keys' => ['*token*', '*secret*', '*auth*'],

// Matches:
// - api_token, access_token, token_data, my_token_field
// - user_secret, secret_key, app_secret_config
// - auth_header, oauth_token, authentication_data
```

#### Prefix Pattern (`word*`)

[](#prefix-pattern-word)

Matches any key that starts with the specified word:

```
'blocked_keys' => ['password*', 'secret*', 'api*'],

// Matches:
// - password, password_hash, password_confirmation
// - secret, secret_key, secret_data
// - api, api_key, api_token, api_endpoint
```

#### Suffix Pattern (`*word`)

[](#suffix-pattern-word)

Matches any key that ends with the specified word:

```
'blocked_keys' => ['*token', '*key', '*secret'],

// Matches:
// - access_token, api_token, user_token
// - private_key, public_key, encryption_key
// - user_secret, app_secret, database_secret
```

#### Multi-Wildcard Patterns (`word*middle*word`)

[](#multi-wildcard-patterns-wordmiddleword)

Use multiple wildcards for complex patterns:

```
'blocked_keys' => [
    'user_*_token',     // user_api_token, user_auth_token
    'app_*_*_key',      // app_private_encryption_key, app_public_signing_key
    '*_key_*',          // my_key_data, the_key_value, user_key_config
],
```

### Case-Insensitive Matching

[](#case-insensitive-matching)

All wildcard patterns are case-insensitive by default:

```
'blocked_keys' => ['*TOKEN*'],

// Matches all of these:
// - API_TOKEN, api_token, Api_Token, MyTokenData, user_token_field
```

### Combining Exact and Wildcard Patterns

[](#combining-exact-and-wildcard-patterns)

You can mix exact matches with wildcard patterns in the same configuration:

```
'blocked_keys' => [
    'password',           // Exact match
    'secret',            // Exact match
    '*token*',           // Wildcard pattern
    '*_key_*',           // Complex wildcard
    'user_*_data',       // Specific structure
],

'safe_keys' => [
    'id',                // Exact match - always preserved
    'user_id',           // Exact match - always preserved
    '*_count',           // Wildcard pattern - preserve counting fields
    'meta_*',            // Wildcard pattern - preserve metadata fields
],
```

### Performance Considerations

[](#performance-considerations)

- Exact matches are faster than wildcard patterns
- Simple wildcards (`*word*`) are faster than complex multi-wildcard patterns
- Consider placing more specific patterns before broader ones
- Use exact matches when you know the specific key names

Common Use Cases
----------------

[](#common-use-cases)

### Logging Context

[](#logging-context)

```
use Kirschbaum\Redactor\Facades\Redactor;

// Before logging user actions
Log::info('User action', Redactor::redact([
    'user_id' => 123,
    'action' => 'login',
    'ip_address' => '192.168.1.1',
    'session_token' => 'abc123def456...',
    'user_agent' => 'Mozilla/5.0...',
    'api_response' => $sensitiveApiData,
]));
```

### Laravel Logging Integration

[](#laravel-logging-integration)

For automatic redaction of all log entries, use the `CustomLogTap` with Laravel's logging configuration. In your `config/logging.php`, add the tap to any channel:

```
'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => explode(',', env('LOG_STACK', 'single')),
        'ignore_exceptions' => false,
        'tap' => [Kirschbaum\Redactor\Logging\CustomLogTap::class],
    ],

    'single' => [
        'driver' => 'single',
        'path' => storage_path('logs/laravel.log'),
        'level' => env('LOG_LEVEL', 'debug'),
        'tap' => [Kirschbaum\Redactor\Logging\CustomLogTap::class],
    ],

    'daily' => [
        'driver' => 'daily',
        'path' => storage_path('logs/laravel.log'),
        'level' => env('LOG_LEVEL', 'debug'),
        'days' => 14,
        'tap' => [Kirschbaum\Redactor\Logging\CustomLogTap::class],
    ],
],
```

With this configuration, all log entries will automatically have their context data redacted before being written to logs. The tap uses the `default` redaction profile unless otherwise configured.

### API Response Sanitization

[](#api-response-sanitization)

```
use Kirschbaum\Redactor\Facades\Redactor;

// Before returning debug information
return response()->json([
    'debug' => Redactor::redact($requestData, 'performance'),
    'status' => 'processed'
]);
```

### Database Export &amp; Auditing

[](#database-export--auditing)

```
use Kirschbaum\Redactor\Facades\Redactor;

// Before exporting user data
$users = User::all()->map(function ($user) {
    return Redactor::redact($user->toArray(), 'strict');
});

// Audit trail with sensitive data redacted
$auditLog = Redactor::redact([
    'user_id' => $user->id,
    'changes' => $changes,
    'request_data' => request()->all(),
], 'audit');
```

### PCI Compliance Example

[](#pci-compliance-example)

```
// config/redactor.php
'profiles' => [
    'pci_compliant' => [
        'enabled' => true,
        'strategies' => [
            \Kirschbaum\Redactor\Strategies\SafeKeysStrategy::class,
            \Kirschbaum\Redactor\Strategies\BlockedKeysStrategy::class,
            \Kirschbaum\Redactor\Strategies\RegexPatternsStrategy::class,
        ],
        'safe_keys' => ['order_id', 'customer_id', 'amount', 'currency'],
        'blocked_keys' => [
            'credit_card', 'cc_number', 'card_number', 'pan',
            'cvv', 'cvc', 'cvn', 'expiry', 'exp_date', 'security_code'
        ],
        'patterns' => [
            'credit_card' => '/\b(?:\d[ -]*?){13,16}\b/',
            'ssn' => '/\b\d{3}-?\d{2}-?\d{4}\b/',
            'routing_number' => '/\b\d{9}\b/',
        ],
        'replacement' => '[PCI_REDACTED]',
        'non_redactable_object_behavior' => 'redact',
    ],
];

// Usage
$orderData = Redactor::redact($order->toArray(), 'pci_compliant');
```

Advanced Features
-----------------

[](#advanced-features)

### Object Handling

[](#object-handling)

The package handles various object types:

```
use Kirschbaum\Redactor\Facades\Redactor;

// Laravel models (uses toArray())
$user = User::find(1);
$redacted = Redactor::redact($user);

// Plain objects (uses JSON serialization)
$object = new stdClass();
$object->secret = 'sensitive';
$redacted = Redactor::redact($object);

// Non-serializable objects (configurable behavior)
$resource = fopen('file.txt', 'r');
$redacted = Redactor::redact(['file' => $resource]);
// Behavior controlled by 'non_redactable_object_behavior' setting
```

### Custom Strategies

[](#custom-strategies)

Create your own redaction logic with full type safety:

```
use Kirschbaum\Redactor\Strategies\RedactionStrategyInterface;
use Kirschbaum\Redactor\RedactionContext;

class InternalDataStrategy implements RedactionStrategyInterface
{
    public function shouldHandle(mixed $value, string $key, RedactionContext $context): bool
    {
        return str_contains($key, 'internal_') || str_contains($key, 'debug_');
    }

    public function handle(mixed $value, string $key, RedactionContext $context): mixed
    {
        $context->markRedacted();
        return '[INTERNAL]';
    }
}

// Register and use
use Kirschbaum\Redactor\Facades\Redactor;

Redactor::registerCustomStrategy('internal_data', new InternalDataStrategy());

// Add to profile configuration
'strategies' => [
    'internal_data', // Custom strategy by registered name
    \Kirschbaum\Redactor\Strategies\SafeKeysStrategy::class,
    // ... other strategies
],
```

### Multiple Usage Patterns

[](#multiple-usage-patterns)

```
// Via Facade (recommended)
use Kirschbaum\Redactor\Facades\Redactor;
$result = Redactor::redact($data, 'profile_name');

// Via Service Container
$redactor = app(\Kirschbaum\Redactor\Redactor::class);
$result = $redactor->redact($data, 'profile_name');

// Direct Instantiation (gets fresh instance - no state conflicts)
$redactor = new \Kirschbaum\Redactor\Redactor();
$result = $redactor->redact($data, 'profile_name');

// Check available profiles
$profiles = Redactor::getAvailableProfiles();
$exists = Redactor::profileExists('custom_profile');
```

Built-in Profiles
-----------------

[](#built-in-profiles)

- **`default`**: Balanced redaction for general logging and debugging
- **`strict`**: Aggressive redaction for sensitive contexts and audit trails
- **`performance`**: Minimal redaction optimized for high-throughput scenarios

Environment Configuration
-------------------------

[](#environment-configuration)

Many settings can be controlled via environment variables:

```
REDACTOR_ENABLED=true
REDACTOR_DEFAULT_PROFILE=default
REDACTOR_REPLACEMENT="[REDACTED]"
REDACTOR_MARK_REDACTED=true
REDACTOR_TRACK_KEYS=false
REDACTOR_OBJECT_BEHAVIOR=preserve
REDACTOR_MAX_VALUE_LENGTH=5000
REDACTOR_LARGE_OBJECTS=true
REDACTOR_MAX_OBJECT_SIZE=100
REDACTOR_SHANNON_ENABLED=true
REDACTOR_SHANNON_THRESHOLD=4.8
REDACTOR_SHANNON_MIN_LENGTH=25
```

File Scanning Command
---------------------

[](#file-scanning-command)

The package includes a console command to scan files and directories for sensitive content:

```
# Scan specific files
php artisan redactor:scan path/to/sensitive-file.txt

# Scan directories (scans entire project by default)
php artisan redactor:scan app/ config/

# Scan with custom profile
php artisan redactor:scan --profile=strict app/

# Exit with error code if sensitive content found (useful for CI)
php artisan redactor:scan --bail app/

# JSON output for programmatic use
php artisan redactor:scan --output=json config/

# Summary only (no per-file details)
php artisan redactor:scan --summary-only
```

The scanner uses the `file_scan` profile by default, which is optimized for plain text content and detects:

- API keys, tokens, and secrets
- Email addresses and personal information
- High-entropy strings (potential keys/tokens)
- Credit cards, SSNs, phone numbers
- Passwords and authentication strings

Results show **CLEAN**, **FINDINGS**, or **SKIPPED** status for each file, with a summary of total files scanned and findings detected.

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

[](#requirements)

- PHP 8.3+
- Laravel 11.x or 12.x

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

[](#installation)

```
composer require kirschbaum-development/redactor
php artisan vendor:publish --tag=redactor-config
```

Testing
-------

[](#testing)

```
# Run tests
./vendor/bin/pest

# Run tests with coverage
./vendor/bin/pest --coverage
```

Roadmap
-------

[](#roadmap)

- Add Laravel custom log formatter to tap logs and automatically redact sensitive data
- Add supoprt for partial replacement of sensitive data (low priority)

License
-------

[](#license)

MIT License. See [LICENSE.md](LICENSE.md) for details.

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance60

Regular maintenance activity

Popularity21

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity47

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

Unknown

Total

1

Last Release

380d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/57e405b52d482c9de35b17f299d2745e8e68d9d9951aec64854f2d7fa53110bf?d=identicon)[luisdalmolin](/maintainers/luisdalmolin)

---

Top Contributors

[![lacieri](https://avatars.githubusercontent.com/u/12892121?v=4)](https://github.com/lacieri "lacieri (2 commits)")

---

Tags

middlewarelaravelsecuritypipelineobservabilitygdprcomplianceprivacyRedactorSensitive datadata redactionlog redactionlog sanitizershannon entropy

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/kirschbaum-development-redactor/health.svg)

```
[![Health](https://phpackages.com/badges/kirschbaum-development-redactor/health.svg)](https://phpackages.com/packages/kirschbaum-development-redactor)
```

###  Alternatives

[spatie/laravel-csp

Add CSP headers to the responses of a Laravel app

86611.1M25](/packages/spatie-laravel-csp)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

816333.8k3](/packages/defstudio-telegraph)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

44855.7k](/packages/harris21-laravel-fuse)[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.

5021.9k](/packages/simplestats-io-laravel-client)[laravel-chronicle/core

Tamper-evident audit ledger for Laravel applications.

1213.2k3](/packages/laravel-chronicle-core)[devrabiul/laravel-cookie-consent

A GDPR-compliant cookie consent solution for Laravel applications with fully customizable cookie banners, granular consent control, and enterprise-grade compliance features.

18355.4k1](/packages/devrabiul-laravel-cookie-consent)

PHPackages © 2026

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