URL fun and games

65 views
Skip to first unread message

Gregory Neagle

unread,
Apr 23, 2026, 12:35:19 PM (13 days ago) Apr 23
to munki-dev
I encountered an interesting issue recently I thought I’d document and share.

We have essentially two Munki servers, an “internal” server, visible only to the internal network, running on a Linux VM, using Apache. The repo it serves is also synced to Amazon S3 storage, which is served via CloudFront, and is (obviously) available eternally to clients.

One of our testers noted a problem getting a certain release of a certain software package:

PastedGraphic-1.png
This seemed strange as we could verify the file (a dmg) was actually present in the repo. But one of our engineers pointed out there was a “+” in the filename (or, actually, two):

pkgs/apps/pcoip-client_26.08.0-rc0+5-8be81eb928-26.08.0rc0+5.dmg

So to simplify testing, I created a test manifest: manifests/greg+test.

I could download it from our local Munki repo server:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>catalogs</key>
<array>
<string>production</string>
</array>
    <!-- snip -->
</dict>
</plist>

But once synced to S3, our Munki client failed to download it:

$ sudo managedsoftwareupdate --id "greg+test" -vvv
Managed Software Update Tool
Version 7.1.0.5685
  <snip>
    Getting manifest greg+test...
  <snip>
    <?xml version="1.0" encoding="UTF-8"?>
<Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Key>manifests/greg test</Key><RequestId>redacted</RequestId><Redacted></Error>

You can see the request was for "manifests/greg+test”, but CloudFront interpreted it as "manifests/greg test”; in other words, it interpreted the + as a space.

A fix/workaround would be for Munki to encode all + signs in URLs as "%2B” — in brief testing that still works with our internal Apache server, but I’m not certain it will work with all web servers. Technically, in URL paths the + should be treated as a literal plus sign, while a space should be encoded as %20. Only in URL query parameters should a + be interpreted as a space.

For now, our fix was to simply rename the disk image to not contain any + characters in the filename.

Curious if others have encountered this, and what your thoughts might be about Munki encoding + as %2B in URL paths.

-Greg

Vaughn Miller

unread,
Apr 23, 2026, 12:47:34 PM (13 days ago) Apr 23
to munk...@googlegroups.com
I have encountered this problem with CloudFront not serving a file with a + in the name.  In my case it is RStudio that has a + in the version string.  Like you I've been renaming the dmg file to not have the +.

Vaughn

--
Find related discussion groups here:
https://github.com/munki/munki/wiki/Discussion-Group
---
You received this message because you are subscribed to the Google Groups "munki-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to munki-dev+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/munki-dev/BE38353E-8748-480A-8FD4-C513D37BFCFE%40mac.com.

Rod Christiansen

unread,
Apr 23, 2026, 1:07:34 PM (13 days ago) Apr 23
to munki-dev
I have also had this issue on Azure FrontDoor with if I recall Reaper audio app, removed the `+`
It also applies `application/x-www-form-urlencoded` semantics and turns it into a space

- Rod

Chris Hart

unread,
Apr 23, 2026, 1:07:42 PM (13 days ago) Apr 23
to munki-dev
I have also encountered this for several years since I had to switch my environment over to IIS. I likewise have been removing the + symbol from the dmg file for several apps in my repo.

Chris H.

Brandon Friess

unread,
Apr 23, 2026, 1:58:46 PM (13 days ago) Apr 23
to munk...@googlegroups.com
Are you using middleware to generate the pre-signed CloudFront URL, or is a server generating it?

I also tested this against the Go-based `munkisrv` implementation at `https://github.com/stripe/munkisrv`, which generates the pre-signed CloudFront URL server-side. In its current form, it preserves a raw `+` in the signed path, which leaves the same downstream ambiguity; if the client sends `%2B`, that currently gets double-encoded to `%252B`. So the issue still seems to point back to needing proper path-segment encoding rather than relying on raw `+` to survive every intermediary.

At any rate, encoding `+` as `%2B` in path segments still seems like a reasonable hardening change for Munki to avoid ambiguity with intermediaries like CloudFront/S3.

Brandon



--

Gregory Neagle

unread,
Apr 23, 2026, 2:22:47 PM (13 days ago) Apr 23
to munki-dev

On Apr 23, 2026, at 10:58 AM, Brandon Friess <bra...@friessfam.com> wrote:

Are you using middleware to generate the pre-signed CloudFront URL, or is a server generating it?

I guess the latter, since I’m using a Lambda@Edge function, ala https://grahamgilbert.com/blog/2018/10/31/deploying-a-munki-repo-in-five-minutes-with-terraform/

-Greg

I also tested this against the Go-based `munkisrv` implementation at `https://github.com/stripe/munkisrv`, which generates the pre-signed CloudFront URL server-side. In its current form, it preserves a raw `+` in the signed path, which leaves the same downstream ambiguity; if the client sends `%2B`, that currently gets double-encoded to `%252B`. So the issue still seems to point back to needing proper path-segment encoding rather than relying on raw `+` to survive every intermediary.

At any rate, encoding `+` as `%2B` in path segments still seems like a reasonable hardening change for Munki to avoid ambiguity with intermediaries like CloudFront/S3.

Brandon



On Thu, Apr 23, 2026 at 11:35 AM 'Gregory Neagle' via munki-dev <munk...@googlegroups.com> wrote:
I encountered an interesting issue recently I thought I’d document and share.

We have essentially two Munki servers, an “internal” server, visible only to the internal network, running on a Linux VM, using Apache. The repo it serves is also synced to Amazon S3 storage, which is served via CloudFront, and is (obviously) available eternally to clients.

One of our testers noted a problem getting a certain release of a certain software package:

Chris Hart

unread,
Apr 24, 2026, 10:50:26 AM (12 days ago) Apr 24
to munki-dev
I first made sure that I could curl an existing manifest successfully. Success. I then created a manifest called "test+manifest" to test. 


It failed with the following error: 404 - File or directory not found.

I then tried with the '%2B'. 


It also failed with the same error: 404 - File or directory not found.

Neither option worked in my IIS environment. So, encoding the URL won't fix it for IIS, but it won't break anything either because it doesn't work without the encoding either.

Chris H.
Reply all
Reply to author
Forward
0 new messages