diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go
index 4c22c4cd8e367a8c1fd6a2acf67f4c789f758dc0..78263fc0b2cc3c459262f40994bf721c997a9db1 100644
--- a/src/crypto/x509/name_constraints_test.go
+++ b/src/crypto/x509/name_constraints_test.go
@@ -1599,6 +1599,24 @@ var nameConstraintsTests = []nameConstraintsTest{
 			cn:   "foo.bar",
 		},
 	},
+
+	// #86: URIs with IPv6 addresses with zones and ports are rejected
+	{
+		roots: []constraintsSpec{
+			{
+				ok: []string{"uri:example.com"},
+			},
+		},
+		intermediates: [][]constraintsSpec{
+			{
+				{},
+			},
+		},
+		leaf: leafSpec{
+			sans: []string{"uri:http://[2006:abcd::1%25.example.com]:16/"},
+		},
+		expectedError: "URI with IP",
+	},
 }
 
 func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 6efbff28bf7b6e997988c46a8197b6f7b1430c5d..2d2a271d53e950b3c141b090ae11b268e9c5c69a 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -11,6 +11,7 @@ import (
 	"errors"
 	"fmt"
 	"net"
+	"net/netip"
 	"net/url"
 	"reflect"
 	"runtime"
@@ -429,8 +430,10 @@ func matchURIConstraint(uri *url.URL, constraint string) (bool, error) {
 		}
 	}
 
-	if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") ||
-		net.ParseIP(host) != nil {
+	// netip.ParseAddr will reject the URI IPv6 literal form "[...]", so we
+	// check if _either_ the string parses as an IP, or if it is enclosed in
+	// square brackets.
+	if _, err := netip.ParseAddr(host); err == nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) {
 		return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String())
 	}