Several filters return the source unchanged (byte-identical to the unfiltered passthrough) when the input is an animated GIF. No error, no warning, just the original bytes back with Content-Type: image/gif.
Tested on v1.8.6. Same animated GIF source for every row, only the filter changes:
| Filter |
Result |
| (no filter) |
passthrough (baseline) |
blur(8) |
no-op (byte-identical to baseline) |
sharpen(50) |
no-op |
pixelate(8) |
no-op |
saturation(-50) |
no-op |
hue(60) |
no-op |
negative() |
no-op |
brightness(30) |
applied (different bytes) |
contrast(30) |
applied |
grayscale() |
applied |
rotate(90) |
applied |
round_corner(20,20,255,255,255) |
applied |
rgb(50,0,0) |
applied |
format(webp) |
applied |
So the no-ops are blur, sharpen, pixelate, saturation, hue, negative. The other filters work fine on the same input. The silent passthrough is hard to spot in client code: caller gets a 200 with valid GIF bytes and assumes it worked.
Repro:
/unsafe/filters:blur(8)/<any animated GIF URL>
Several filters return the source unchanged (byte-identical to the unfiltered passthrough) when the input is an animated GIF. No error, no warning, just the original bytes back with
Content-Type: image/gif.Tested on v1.8.6. Same animated GIF source for every row, only the filter changes:
blur(8)sharpen(50)pixelate(8)saturation(-50)hue(60)negative()brightness(30)contrast(30)grayscale()rotate(90)round_corner(20,20,255,255,255)rgb(50,0,0)format(webp)So the no-ops are
blur,sharpen,pixelate,saturation,hue,negative. The other filters work fine on the same input. The silent passthrough is hard to spot in client code: caller gets a 200 with valid GIF bytes and assumes it worked.Repro: