Fixing Imagick's “not authorized” exception

Over the last few days we've had a couple of issues with Imagick and processing PDFs on our servers. As it turns out, these issues are caused by automatic security updates. Let's look into the issue and its solution.

In Bugsnag, our error reporting service, the following exceptions have been popping up a lot:

not authorized `/path/to/some-pdf.pdf` @ error/constitute.c/ReadImage/412

convert: not authorized `/path/to/some-pdf.pdf` @ error/constitute.c/WriteImage/1028

not authorized `/path/to/some-image.png` @ error/convert.c/ConvertImageCommand/3015

unable to create temporary file `/some/path` Permission denied @ error/pdf.c/ReadPDFImage/465

Upon further investigation it looks like most of our sites and applications dealing with PDFs were actually experiencing issues. The weird thing is, some of these applications are quite old and haven't been updated or even touched for months, whilst others are recent and running the latest versions of packages and OS.

I don't care about your problems, just give me the fix!

A recent ImageMagick security update adds some extra policies regarding PDFs (or more specifcally: Ghostscript). We can actually see the diff for this update right here. Luckily, we can edit the policy.xml file ourselves and loosen up security for working with PDFs.

In /etc/ImageMagick-6/policy.xml (or /etc/ImageMagick/policy.xml) find the following line

<policy domain="coder" rights="none" pattern="PDF" />

and change it to allow reading and writing by the PDF coder in ImageMagick:

<policy domain="coder" rights="read|write" pattern="PDF" />

Finally, don't forget to restart your PHP-FPM and optionally queue workers:

sudo service php7.2-fpm restart

If you're experiencing issues with other file types or manipulations, you might need to change some of the other policies as well. The policy.xml file contains some good documentation in the comments. You can read more about the security policy file on ImageMagick's website.

Bulk patching using Ansible

When managing a lot of applications, it might be a worth considering something like Ansible to quickly set-up, manage and patch all of your servers.

My colleague Ruben wrote an excellent Ansible playbook to apply the above fix. It deals with the different ImageMagick directories as well!

- name: Find ImageMagick directories
    paths: /etc
    pattern: "ImageMagick(?:-\\d)"
    file_type: directory
    use_regex: yes
  register: imagemagick_directories

- name: Allow ImageMagick coder to read and write
    dest: "{{ item.path }}/policy.xml"
    regexp: '\s*<policy domain="coder" rights="none" pattern="PDF" />'
    line: '  <policy domain="coder" rights="read|write" pattern="PDF" />'
    backrefs: yes
  with_items: "{{ imagemagick_directories.files }}"

The culprit

As it turns out, these issues are caused by a recent security update for the ImageMagick package that was released on the 28th of September, 2018. The changelog for this update can be found here..

One of the first changes in the log is "disable ghostscript handled types by default in policy.xml". It just so happens that Ghostscript is used for all sorts of PDF manipulations, either directly or under the hood in many packages (including some of our own like spatie/laravel-media-library, spatie/pdf-to-image and spatie/pdf-to-text).

Depending on your server configuration you might never run into this issue. For example, Ubuntu doesn't install updates automatically out of the box. However, a lot of server provisioners (like Laravel Forge) will install the unattended-upgrades package on new servers. This package will periodically pull in these kind of updates and thus magically break your application.

You can check if you're running the unattended-upgrades package using the following command:

dpkg -l | grep unattended-upgrades

Some closing thoughts

On top of being able to quickly fix and patch these kind of issues, it's always a good idea to use some kind of error reporting service. This way you can quickly identify which of your applications and websites are affected. (Unless the service you're using doesn't allow you to globally search exceptions in all projects, looking at you, Bugsnag)