Repository navigation
Laravel instrumentation: url.full is recorded unredacted, leaking signed-URL signatures #2028
Description
What happens
opentelemetry-auto-laravel records the full request URL, including the query string, with no redaction of sensitive query parameters.
Server spans — src/Hooks/Illuminate/Contracts/Http/Kernel.php:58:
->setAttribute(TraceAttributes::URL_FULL, $request->fullUrl())Client spans — src/Watchers/ClientRequestWatcher.php:50-55 strips userinfo, then re-appends the query string verbatim:
$parsedUrl = collect(parse_url($request->request->url()) ?: []);
$processedUrl = $parsedUrl->get('scheme', 'http') . '://' . $parsedUrl->get('host') . $parsedUrl->get('path', '');
if ($parsedUrl->has('query')) {
$processedUrl .= '?' . $parsedUrl->get('query'); // <- unredacted
}Why this matters for Laravel specifically
Laravel's signed URLs are a core framework feature used for email verification, password-reset style flows and temporary download links. UrlGenerator::signedRoute() / temporarySignedRoute() append the HMAC as a query parameter:
// Illuminate/Routing/UrlGenerator.php:365,373
$parameters = $parameters + ['expires' => $this->availableAt($expiration)];
...
'signature' => hash_hmac('sha256', $this->route($name, $parameters, $absolute), $key),The name is hardcoded and reserved — Laravel throws InvalidArgumentException if an application tries to use signature or expires as a route parameter (UrlGenerator.php:391,460). There is no configuration option.
So the value that authorises the request is captured in the span, and remains replayable until expires. This affects every Laravel application using this instrumentation, not a particular configuration.
Expected behaviour per the semantic conventions
The requirement is already vendored into this project as PHPDoc on the very constant the instrumentation sets — sem-conv/Attributes/UrlAttributes.php, above const URL_FULL:
Sensitive content provided in
url.fullSHOULD be scrubbed when instrumentations can identify it.Query string values for the following keys SHOULD be redacted by default and replaced by the value
REDACTED:
AWSAccessKeyIdSignaturesigX-Goog-SignatureWhen a query string value is redacted, the query string key SHOULD still be preserved, e.g.
https://www.example.com/path?color=blue&sig=REDACTED.
The URL attribute registry places this on the instrumentation, and notes instrumentations MAY allow the list to be overridden.
Current state
grep -riE 'scrub|sanitiz|redact' --include='*.php' across open-telemetry/sdk, open-telemetry/api, open-telemetry/sem-conv and opentelemetry-auto-laravel returns matches only inside PHPDoc comments in sem-conv, plus SanitizeCombinedHeadersPropagationGetter in context, which concerns combined header values rather than URLs.
There appears to be no executable query-parameter redaction anywhere in the PHP implementation, and no configuration surface for it. Userinfo is handled only in ClientRequestWatcher, and not on server spans.
Question: is key matching intended to be case-sensitive?
The default list contains Signature (capitalised, from the AWS S3 query-auth docs). Laravel emits lowercase signature. A case-insensitive implementation would cover Laravel out of the box; a case-sensitive one would not.
The specification does not appear to state this. Clarifying it would be valuable, since the difference decides whether the most widely used PHP framework's signed URLs are protected by the default list or need an override.
Reproduction
- Laravel 12 app with
open-telemetry/opentelemetry-auto-laravelandOTEL_PHP_AUTOLOAD_ENABLED=true - Define a signed route and generate a link with
URL::temporarySignedRoute('verify', now()->addMinutes(60), ['id' => 1]) - Request the URL and inspect the exported span
url.full contains the complete ?expires=…&signature=….
Suggested fix
- Redact the documented default keys in both
Kernel.php(server spans) andClientRequestWatcher.php(client spans), preserving keys and replacing values withREDACTED. - Consider a shared helper in
open-telemetry/sdk, since every instrumentation settingurl.fullorurl.queryneeds identical behaviour. - Expose an override so applications can add framework-specific keys —
signaturefor Laravel, if matching turns out to be case-sensitive. - Clarify case-sensitivity in the specification, or handle it case-insensitively.
Happy to open a PR if the maintainers agree on the approach and where the helper should live.
Environment
open-telemetry/opentelemetry-auto-laravel |
1.8.0 |
open-telemetry/sdk |
1.15.0 |
open-telemetry/api |
1.10.0 |
laravel/framework |
v12.64.0 |
| PHP | 8.4 |
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity
ChrisLightfootWild commentedon Aug 12, 2026
Thanks for flagging this @hnccox 👍
There's an existing mechanism which would handle the sanitization here, but it is a more recent addition to contrib and has not yet been wired into any pre-existing instrumentation.
https://github.com/open-telemetry/opentelemetry-php-contrib/tree/main/src/Instrumentation/HttpConfig
See examples here.
I do have an (unfortunately stale 👀) PR here to move Laravel towards using SPI based configuration, which it would make sense to also add this to.
bobstrecansky commentedon Sep 23, 2026
@ChrisLightfootWild mentioned he'd like to land this first: open-telemetry/opentelemetry-php-contrib#269
ChrisLightfootWild commentedon Oct 10, 2026
I am planning on picking this up after 1.10 is released.
ChrisLightfootWild commentedon Oct 11, 2026
I have a local draft of this using https://github.com/open-telemetry/opentelemetry-php-contrib/tree/main/src/Instrumentation/HttpConfig
Aiming to open a PR this week.