An implementation issue with subresource integrity checks in import maps

An implementation issue with subresource integrity checks in import maps

Last year, the major browser vendors implemented a feature that was missing for resources referenced by import maps: integrity checks. Earlier these were implemented on the individual script or link tags like this:

<script
  src="https://example.com/example-framework.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"></script>

Example taken from MDN

The idea is that a cryptographic hash is attached to the linked resource that allows the browser to verify the integrity of the file and make sure no one snuck in a different file with malware in it. It's a great idea that even lets you safely use CDN's which are otherwise quite a security risk.

So it was an obvious addition to import maps as well, as an import map is just a list of references to external files.

So here is the implementation they made for it, this time my own example.

<script type="importmap">
	{
		"imports": {
			"foobar": "https://example.com/FooBar.js",
		},
		"integrity": {
			"https://example.com/Foobar.js": "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
		}
	}
</script>

The import and the integrity hash are separate from each other. First the import specifier "foobar" is associated with a reference link, then the integrity hash is added and associated with the aforementioned link.

But did you spot the error in the example above?

The specifier references "FooBar.js" and the integrity hash "Foobar.js", a minor misspelling. But this little issue has quite serious implications: The integrity of "FooBar.js" will not be checked because those two paths reference two different files and malicious changes to FooBar.js will just be accepted by the browser.

However, I think what is even more troublesome is the fact that developers will still believe their integrity checks are active and working, giving them a false sense of security.

The main culprit here is the double reference to the resource location. This is where I believe we are actually looking at an implementation issue.

A clearer approach to integrity checks would have been:

<script type="importmap">
	{
		"imports": {
			"foobar": {
				url: "https://example.com/FooBar.js",
				integrity: "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
            }
		}
	}
</script>

It is a bit more convoluted and adds another level of depth, but it's clear and without repeating yourself. This way the browser would have a direct relation between url and hash, there would be less room for error and even if an error occurred, the browser could pick up on it and alarm the user.

Discussion