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.full SHOULD 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:
AWSAccessKeyId
Signature
sig
X-Goog-Signature
When 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-laravel and OTEL_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) and ClientRequestWatcher.php (client spans), preserving keys and replacing values with REDACTED.
- Consider a shared helper in
open-telemetry/sdk, since every instrumentation setting url.full or url.query needs identical behaviour.
- Expose an override so applications can add framework-specific keys —
signature for 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 |
What happens
opentelemetry-auto-laravelrecords 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:Client spans —
src/Watchers/ClientRequestWatcher.php:50-55strips userinfo, then re-appends the query string verbatim: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:The name is hardcoded and reserved — Laravel throws
InvalidArgumentExceptionif an application tries to usesignatureorexpiresas 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, aboveconst URL_FULL: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'acrossopen-telemetry/sdk,open-telemetry/api,open-telemetry/sem-convandopentelemetry-auto-laravelreturns matches only inside PHPDoc comments insem-conv, plusSanitizeCombinedHeadersPropagationGetterincontext, 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 lowercasesignature. 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
open-telemetry/opentelemetry-auto-laravelandOTEL_PHP_AUTOLOAD_ENABLED=trueURL::temporarySignedRoute('verify', now()->addMinutes(60), ['id' => 1])url.fullcontains the complete?expires=…&signature=….Suggested fix
Kernel.php(server spans) andClientRequestWatcher.php(client spans), preserving keys and replacing values withREDACTED.open-telemetry/sdk, since every instrumentation settingurl.fullorurl.queryneeds identical behaviour.signaturefor Laravel, if matching turns out to be case-sensitive.Happy to open a PR if the maintainers agree on the approach and where the helper should live.
Environment
open-telemetry/opentelemetry-auto-laravelopen-telemetry/sdkopen-telemetry/apilaravel/framework