Bug description
With image_manipulation.secure enabled, every Glide request returns 400 Signature is not valid. if the site's url in sites.yaml is on a different domain from the one serving Statamic.
We hit this running Statamic headless. The site URLs point at our frontend (https://www.example.com) so entry URLs come out right, while Statamic and its /img route are on https://cms.example.com.
GlideController::validateSignature() works out the path to check like this:
$path = Str::after($this->request->url(), Site::current()->absoluteUrl());
For a request to https://cms.example.com/img/..., the site URL is https://www.example.com. That isn't part of the request URL, so Str::after() returns the whole URL. The signature was generated over /img/..., so it never matches.
One possible fix is to fall back to the request path when the site URL isn't a prefix of the request URL:
$url = $this->request->url();
$siteUrl = Site::current()->absoluteUrl();
$path = Str::startsWith($url, $siteUrl)
? Str::after($url, $siteUrl)
: $this->request->getPathInfo();
Sites with a path prefix (/de/img/...) still take the first branch, so their URLs keep working. Using getPathInfo() on its own would break them.
How to reproduce
- Set a site's
url in resources/sites.yaml to a different domain from the app, for example https://www.example.com while the app runs on http://localhost.
- Leave
statamic.assets.image_manipulation.secure at its default of true.
- Generate a URL with
Image::manipulate('image.jpg', ['w' => 300]). It comes back relative, as /img/image.jpg?w=300&s=....
- Request it from the app:
http://localhost/img/image.jpg?w=300&s=.... The response is 400 Signature is not valid.
If you change the site URL to http://localhost, the same URL passes the signature check.
Logs
N/A
Environment
Statamic 6.33.0, league/glide 4.1.0, PHP 8.5.0, Laravel 13.32.0. The same line is still in GlideController in 6.34.0.
Installation
Existing Laravel app
Additional details
My colleague Andrius Gluzeckis found this.
Bug description
With
image_manipulation.secureenabled, every Glide request returns400 Signature is not valid.if the site'surlinsites.yamlis on a different domain from the one serving Statamic.We hit this running Statamic headless. The site URLs point at our frontend (
https://www.example.com) so entry URLs come out right, while Statamic and its/imgroute are onhttps://cms.example.com.GlideController::validateSignature()works out the path to check like this:For a request to
https://cms.example.com/img/..., the site URL ishttps://www.example.com. That isn't part of the request URL, soStr::after()returns the whole URL. The signature was generated over/img/..., so it never matches.One possible fix is to fall back to the request path when the site URL isn't a prefix of the request URL:
Sites with a path prefix (
/de/img/...) still take the first branch, so their URLs keep working. UsinggetPathInfo()on its own would break them.How to reproduce
urlinresources/sites.yamlto a different domain from the app, for examplehttps://www.example.comwhile the app runs onhttp://localhost.statamic.assets.image_manipulation.secureat its default oftrue.Image::manipulate('image.jpg', ['w' => 300]). It comes back relative, as/img/image.jpg?w=300&s=....http://localhost/img/image.jpg?w=300&s=.... The response is400 Signature is not valid.If you change the site URL to
http://localhost, the same URL passes the signature check.Logs
N/A
Environment
Statamic 6.33.0, league/glide 4.1.0, PHP 8.5.0, Laravel 13.32.0. The same line is still in
GlideControllerin 6.34.0.Installation
Existing Laravel app
Additional details
My colleague Andrius Gluzeckis found this.