Safeguard
Developer Tools•

Are Go module paths case sensitive? What the exclamation mark means

Go proxies encode each uppercase letter in a module path as an exclamation mark plus the lower case letter. Why, and what it means for name matching.

Safeguard Security Team
4 min read

Go treats module paths as distinct strings, so example.com/M and example.com/m can be different modules. Because many filesystems ignore case, the module proxy protocol encodes each uppercase letter as an exclamation mark followed by its lower case form. That is why you sometimes see !m in a URL or cache path.

What the reference says

The Go Modules Reference describes the proxy protocol. To avoid ambiguity when serving from case insensitive file systems, the module and version elements of a request are case encoded by replacing every uppercase letter with an exclamation mark and the matching lower case letter. The reference gives the example that example.com/M is encoded as example.com/!m, which lets both example.com/M and example.com/m be stored on disk without colliding.

The same encoding applies to versions, since a version can contain letters in a pre-release suffix.

Where you meet it

You will see the encoded form in module proxy URLs, in the module cache on disk, and in logs from a private proxy or mirror. A path with a capital letter in a GitHub username or repository name is common in Go imports, and each such capital shows up as an exclamation mark in the cache directory.

A few examples of how to read it:

Original pathEncoded form
example.com/Mexample.com/!m
example.com/MyLibexample.com/!my!lib
example.com/mexample.com/m

The third row shows why the encoding exists. Without it, the first and third could land in the same folder on a case insensitive disk.

Why it matters for security work

Name matching is the heart of vulnerability scanning and SBOM work. A scanner that lower cases every package name before matching would treat example.com/M and example.com/m as one package. Whether that is a harmless convenience or a source of wrong results depends on the ecosystem, and the Go reference suggests case is meaningful here.

There are two practical risks.

First, a false match. If an advisory names one path and a different module differs only by case, a case folding comparison could attach the advisory to the wrong module.

Second, a missed match. If your tool reads encoded paths from a cache directory and does not decode them, !my!lib will not equal MyLib, and an advisory for MyLib will not match.

Steps to check your tooling

  1. Find a Go module in your build whose path contains an uppercase letter.
  2. Look at how your scanner or SBOM lists it. Is the path shown as written in go.mod, or in the encoded form?
  3. If the output shows an exclamation mark, the tool is exposing the cache encoding and may fail to match advisories. Raise it with the vendor or normalise before matching.
  4. Keep the original path from go.mod in the SBOM, as it is the identifier other tools will use.
  5. If you run a private proxy, check that it follows the encoding in the reference.

Keep it in proportion

Most Go dependencies use lower case paths, so this will rarely bite. But when it does, the cause is hard to spot, because the module builds fine and the scan simply returns nothing. A five minute check on one capitalised path tells you whether your pipeline is safe from this class of problem.

Safeguard's SBOM and dependency scanning records components for your projects, and the free scan lets you see how paths appear in the result.

Quick check

How is example.com/M encoded for a Go proxy?

As example.com/!m. Each uppercase letter becomes an exclamation mark followed by the lower case letter.

Should an SBOM store the encoded path?

No. Store the path as written in go.mod. The encoding is a protocol and storage detail.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.