---
title: "Secrets out of stack traces — Crypto for Laravel | Roundly"
description: "Every frame a secret passes through marks it #[\\SensitiveParameter] — keys, signatures, tokens, codec and loader input, and flat facade calls."
url: https://roundly-consulting.com/open-source/docs/crypto-for-laravel/stack-traces
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Crypto for Laravel](https://roundly-consulting.com/open-source/docs/crypto-for-laravel.md)

# Secrets out of stack traces

PHP hides an argument from a stack trace only in the frame of a function that marks it #\[\\SensitiveParameter\]. So the package marks every frame a secret passes through, not just the entry point — an exception thrown deep inside a verifier, a codec or a loader never carries a key, a token or an OTP secret into your logs and error reports.

## What is marked

- Keys, secrets, peppers and private PEMs, OTP secrets and codes, and plaintext passed to Aes256Gcm.
- Both inputs of ConstantTime::equals() and Crypto::constantTimeEquals(), as PHP marks both of hash\_equals()’s — the expected value is the secret, MAC, token or OTP itself.
- The compact token in Jws::verify(), because a JWS is usually a bearer credential.
- Every signature, HMAC or public-key alike, in each frame that receives one whole: Hmac::verify(), Hs::verify(), Rs::verify(), Es::verify(), EdDSA::verify(), the Verifier contract, KeyVerifier::verify() (Crypto::verifier()), the ECDSA codec (Crypto::ecDer()->fromRaw() / toRaw() / isValid()) and the FlattenedJws constructor. A JWS verification frame also holds the signing input (header.payload), and the two together rebuild the bearer token.
- The data passed to Digest::raw(), hex() and withPepper() — tokens, passwords, personal data.
- The input of every codec — Base32, Base64, Base64Url, Hex and the Crypto::\*Encode() / \*Decode() methods — since OTP secrets, token bytes and keys pass through them. An OTP secret copied with spaces that fails to decode never shows up in the trace of Totp::verify(), Hotp::at() or ProvisioningUri::totp().
- The input of every loader of public material: RsaKey::public(), EcKey::public(), OkpKey::ed25519(), Jwk::fromArray() / fromJson(), Certificate::fromPem() / fromDer() / fromBase64() and Chain::fromPems() / fromX5c() / fromPemBundle(), with their Crypto::keys() and Crypto::x509() forms. Private keys come in the same formats, so one handed over by mistake — the wrong file, a key-only bundle, a private or symmetric JWK — stays out of the trace of the exception that refuses it.

Not marked: messages you sign, MAC or verify (the signing input alone is no credential), ciphertext, nonces, associated data, public key objects, single key components (EC coordinates, an RSA modulus or exponent), COSE\_Key / CBOR input from an authenticator (WebAuthn never hands you a private key), and algorithm, length, label, disk, path or config-key arguments. An architecture test pins the marked set.

## Flat facade calls too

Laravel’s stock Facade::\_\_callStatic() frame records every argument it forwards. The Crypto facade replaces it with package-toolkit’s RedactsSensitiveArguments, which wraps each argument the manager marks in a SensitiveParameterValue in that frame and leaves the others visible. So Crypto::constantTimeEquals($known, $user), Crypto::base64Decode($secret), Crypto::provisioningUri($secret, …) and the loader shortcuts Crypto::jwkFromJson() / jwkFromArray(), Crypto::certificate() and Crypto::chainFrom\*() keep a secret out of the trace just like the class, a sub-accessor or an injected CryptoManager does. Calls that return an object first, like Crypto::totp()->verify($secret, $code), never pass the secret through the facade at all.

## Your own Verifier

PHP does not carry #\[\\SensitiveParameter\] over from an interface. A Verifier you implement yourself must mark its own $signature parameter, as the contract and every package verifier do — see Signers & algorithms.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/crypto-for-laravel.md)
