Skip to content

Redact secret-bearing environment variables - #3

Merged
dp88 merged 2 commits into
mainfrom
redact-environment-secrets
Sep 10, 2026
Merged

dp88 merged 2 commits into
mainfrom
redact-environment-secrets

Conversation

@dp88

@dp88 dp88 commented Sep 10, 2026

Copy link
Copy Markdown
Member

The problem

phpinfo() prints the whole process environment three times: once under Environment as APP_KEY, and twice under PHP Variables as $_ENV['APP_KEY'] and $_SERVER['APP_KEY'].

On a Laravel app that puts the encryption key, the database password and every third-party credential on one page in plaintext. One real panel showed 21 secret-bearing variables, 63 rows. The page is gated to trusted admins, so this is not anonymous exposure. A screenshot, a shared screen, a support session, or any XSS on the panel still leaks the whole credential set at once.

This is standard phpinfo() behaviour, not a regression. It has been true since the package shipped.

The change

Redaction::value() replaces the value of a variable whose name contains a sensitive pattern. It keeps the row, so the page still shows which variables are set.

Default patterns: KEY, SECRET, PASSWORD, TOKEN, CREDENTIAL, PRIVATE, SALT, SIGNING, SIGNATURE, DSN, LICENSE, WEBHOOK.

Two details make this safe to turn on by default:

  1. Matching is scoped to the Environment and PHP Variables modules. Those are the only two places phpinfo() prints the environment. Every other module holds PHP settings, where Max keys, Cached keys, Hash keys restarts, Tokenizer Support and highlight.keyword all match the patterns but hold no secret. A test walks a real capture and asserts nothing outside the two modules is redacted.
  2. All three row forms reduce to the bare variable name before matching, so APP_KEY, $_ENV['APP_KEY'] and $_SERVER['APP_KEY'] are treated alike.

An unset or empty variable is left alone. It leaks nothing, and the blank tells you it is not set.

Configuration

Option Default
redact-environment true
redact-patterns Redaction::DEFAULT_PATTERNS
redact-placeholder [redacted]

The keys are flat, so mergeConfigFrom gives an already-published config file the new defaults. A nested array would not.

Tests

tests/RedactionTest.php, 31 new cases. Both directions are covered: the patterns redact, and the PHP settings that read like secrets do not. vendor/bin/pest is green at 46 passed.

Not in this PR

The view still builds its tables from x-filament-tables::table/row/cell, which Filament 4 removed. composer.json and CI both claim v4 and v5 support, and CI stays green because no test renders the page. Worth a separate issue.

phpinfo() prints the whole process environment three times: as APP_KEY under
Environment, and as $_ENV['APP_KEY'] and $_SERVER['APP_KEY'] under PHP
Variables. On a Laravel app that renders the encryption key, the database
password and every third-party credential on one page.

Redaction::value() replaces the value of a variable whose name contains a
sensitive pattern. The row stays, so the page still shows which variables are
set. Matching is scoped to the two environment modules, so PHP settings such
as "Max keys", "Tokenizer Support" and "highlight.keyword" keep their values.

Config controls the behaviour: redact-environment turns it off, redact-patterns
changes the set, redact-placeholder changes the text. The keys are flat, so
mergeConfigFrom gives an already-published config file the new defaults.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dp88

dp88 commented Sep 10, 2026

Copy link
Copy Markdown
Member Author

Both red legs are pre-existing. They fail at composer update, before any code loads: Composer blocks every Laravel 11 release on security advisories. Unmodified main fails the same way. fail-fast cancelled a third leg that had already passed.

Laravel 11 is past its security-support window, so Composer now refuses to
load any 11.x release and both Laravel 11 legs die at composer update. The
failure predates this branch: origin/main resolves the same matrix leg the
same way.

Those legs check that the package still works on Laravel 11, not that Laravel
11 is patched, so turn off advisory blocking for them alone. Every other leg
keeps it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dp88

dp88 commented Sep 10, 2026

Copy link
Copy Markdown
Member Author

Fixed in c892a3d. The Laravel 11 legs now skip advisory blocking; every other leg keeps it. All 16 checks pass.

Whether the package should still claim Laravel 11 support is a separate call, and yours.

@dp88
dp88 merged commit 1270038 into main Sep 10, 2026
16 checks passed
@dp88
dp88 deleted the redact-environment-secrets branch September 10, 2026 21:01
@dp88 dp88 mentioned this pull request Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant