Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Scrubber Laravel Package

yorcreative/laravel-scrubber

A Laravel package that automatically scrubs sensitive data such as passwords, API keys, and PII from logs, requests, and model output, with configurable redaction rules to keep private information out of your application's records.

Deep Wiki
Context7

Getting Started

Install the package and publish its configuration:

composer require yorcreative/laravel-scrubber
php artisan vendor:publish --tag=scrubber-config

Then open config/scrubber.php before writing any code. That file is the contract for the whole package — it tells you which keys, patterns, and contexts are considered sensitive, and therefore what the scrubber will touch. Read it top to bottom, compare it against your own config/logging.php, and only then decide where to wire the scrubber in.

The first use case should be the narrowest and highest-value one: stop credentials and PII from landing in application logs. Do this before touching request/response scrubbing or exception reporting — logs are where accidental leaks actually persist, get shipped to third-party aggregators, and outlive the request.

A minimal first integration usually looks like one of these, depending on how the package exposes itself:

  • A log processor/tap registered on your logging channel so every record is scrubbed before it hits the handler.
  • A middleware added to the web/api groups for request-level scrubbing.
  • A facade/service call for explicit, in-code scrubbing of a payload.

Start with the log path, verify it with a deliberate leak, then expand. Check the package's README for the exact registration mechanism (service provider auto-discovery, channel tap class, or middleware alias) — the config file and the service provider's register()/boot() are the two places to look first if the docs are thin.

Implementation Patterns

Log-channel tap (recommended default). Register the scrubber as a processor on the channels that leave your infrastructure — typically stack, daily, and any Slack/Papertrail/Datadog handlers. Scrubbing at the handler boundary means every Log::info(), report(), and framework-generated log line passes through it without developers having to remember anything. This is the pattern with the best coverage-to-effort ratio.

Global middleware for inbound requests. Use middleware when you want a scrubbed copy of the request available for logging, auditing, or downstream error reporting. Scrub into a separate attribute rather than mutating the request, so validation and business logic still see the real values — scrubbing is an output concern, not an input concern. Restrict the middleware to routes that actually handle sensitive payloads; running regexes over every request is wasted work.

Explicit scrubbing at the boundary of trust. For jobs that forward data to third parties, webhook dispatchers, or audit tables, call the scrubber directly:

$safe = Scrubber::scrub($payload);        // or the package's equivalent
Log::channel('audit')->info('payload', $safe);

This is the pattern to use for queued jobs and console commands, where HTTP middleware never runs. If you have dispatch() calls carrying sensitive props, scrub in the job's handle() before any Log:: or external call, and consider implementing __sleep()/__wakeup() or WithoutOverlapping-style guards if serialized payloads are a concern.

Exception handler integration. Wire the scrubber into bootstrap/app.php's withExceptions() (Laravel 11+) or app/Exceptions/Handler.php so report() output is redacted. This is where stack traces, request dumps, and model attributes most often leak — exception reporters love to serialize the entire request and all bound models.

Config-first redaction map. Keep your sensitive key list in config rather than hardcoding it: password, password_confirmation, token, api_key, secret, authorization, cookie, session, card_number, cvv, ssn. Add project-specific keys (stripe_id, iban, internal employee IDs) as you discover them. Treat this list as a living document reviewed alongside any new integration.

Layered defense. Pair the scrubber with Laravel's built-in $dontFlash and $except/$hidden on models. The scrubber catches ad-hoc arrays and strings; $hidden catches Eloquent serialization; $dontFlash protects session flash on validation failures. None of them replace the others.

Testing pattern. Write a test that logs a known canary value (e.g. Log::info('test', ['password' => 'CANARY-123'])) against a real channel with the tap attached, then assert the canary is absent from the written file. Do this once per channel you consider "leaving the building." This catches config-cache and channel-misconfiguration bugs that unit tests on the scrubber class will miss.

Gotchas and Tips

Scrubbing is not redaction of the message string. Most implementations walk array keys and string values. A password interpolated directly into a message ("Login failed for {$password}") has no key to match against. Check whether the package scans free-text with patterns; if it doesn't, keep secrets out of message strings by convention or add a custom pattern. This is the single most common source of leaks that survive a "we use a scrubber" claim.

Nested and JSON-encoded payloads. Sensitive data hides inside json_encode()d strings, serialized models, and deeply nested arrays. Confirm the scrubber recurses, and confirm it decodes/recurses into JSON strings if your logs store context as JSON. Test with three levels of nesting and with a JSON string as a value — both are classic blind spots.

Regex over-scrubbing. Broad patterns (anything matching \d{16} as a card number, [A-Za-z0-9]{32} as a key) will mangle legitimate data — order IDs, hashes, UUIDs, timestamps. When a scrubber starts corrupting useful logs, the fix is almost always to tighten patterns or scope them to specific keys, not to disable the scrubber. Keep a fixture file of real log lines and assert they survive unchanged.

Config caching. php artisan config:cache in deployment means config changes require a re-cache. If scrubbing "stopped working" after a deploy, this is the first thing to check. Also verify the published config merged rather than replaced package defaults — a shallow array_merge on nested keys silently drops default patterns.

Silent failure modes. The scrubber runs on the error path. If it throws (bad regex, non-UTF-8 input, unexpected type), you can lose the log line entirely or, worse, trigger a recursive error loop. Check whether the package wraps its own failures, and add a fallback channel or LOG_STACK isolation for critical channels. Test with binary strings and null/int values, not just arrays.

Performance on hot paths. Regex-heavy scrubbing on every log line and every request is not free. Measure before enabling globally on a high-throughput API. The common compromise: full scrubbing on outbound channels (stack, external handlers), minimal or no scrubbing on local/stderr in development.

False sense of security. This package reduces accidental leakage; it does not make it safe to log secrets. It won't catch a secret in a URL path logged by a proxy, in a queued job's serialized payload sitting in Redis, in a Sentry breadcrumb captured before your handler runs, or in a query log with DB::listen. Audit those surfaces separately. Treat the scrubber as one control, not the control.

Extension points to know. Before writing your own wrapper, check for: a custom scrubber/strategy interface for domain-specific patterns, a way to register additional keys at runtime (useful for tenant-specific fields), and an "allow list" or bypass for debugging. If the package lacks runtime registration, a small service provider that merges extra keys into config at boot is usually cleaner than forking.

Version and license notes. MIT, actively released (last release 2026-09-10), 158 stars — a small, single-maintainer-scale package. Pin the version in composer.json, read the changelog before minor bumps (config key renames are common in packages this size), and keep a test that asserts your canary is scrubbed so a broken upgrade fails CI rather than production.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console