This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-node-casbin.git


The following commit(s) were added to refs/heads/master by this push:
     new 9f5bb07  fix: reject out-of-range CIDR prefix in ipMatch
9f5bb07 is described below

commit 9f5bb078ab8a84f34735c15f0ebfe32da8ae1db9
Author: Yang Luo <[email protected]>
AuthorDate: Sat Oct 10 01:44:20 2026 +0800

    fix: reject out-of-range CIDR prefix in ipMatch
---
 src/util/builtinOperators.ts | 25 ++++++++++++++++++++-----
 src/util/ip.ts               | 13 ++++++++++---
 test/util.test.ts            | 27 +++++++++++++++++++++++++++
 3 files changed, 57 insertions(+), 8 deletions(-)

diff --git a/src/util/builtinOperators.ts b/src/util/builtinOperators.ts
index 89d718d..d05800c 100644
--- a/src/util/builtinOperators.ts
+++ b/src/util/builtinOperators.ts
@@ -82,7 +82,11 @@ function keyMatch2(key1: string, key2: string): boolean {
     if (!key2.includes('/:')) {
       break;
     }
-    key2 = key2.replace(regexp, '$1[^/]+$2');
+    const replaced = key2.replace(regexp, '$1[^/]+$2');
+    if (replaced === key2) {
+      break;
+    }
+    key2 = replaced;
   }
 
   if (key2 === '*') {
@@ -140,7 +144,11 @@ function keyMatch3(key1: string, key2: string): boolean {
     if (!key2.includes('/{')) {
       break;
     }
-    key2 = key2.replace(regexp, '$1[^/]+$2');
+    const replaced = key2.replace(regexp, '$1[^/]+$2');
+    if (replaced === key2) {
+      break;
+    }
+    key2 = replaced;
   }
 
   return regexMatch(key1, '^' + key2 + '$');
@@ -180,7 +188,11 @@ function keyMatch4(key1: string, key2: string): boolean {
     if (!key2.includes('/{')) {
       break;
     }
-    key2 = key2.replace(regexp, '$1([^/]+)$2');
+    const replaced = key2.replace(regexp, '$1([^/]+)$2');
+    if (replaced === key2) {
+      break;
+    }
+    key2 = replaced;
   }
 
   regexp = new RegExp('^' + key2 + '$');
@@ -248,7 +260,11 @@ function KeyMatch5(key1: string, key2: string): boolean {
     if (!key2.includes('/{')) {
       break;
     }
-    key2 = key2.replace(regexp, '$1[^/]+$2');
+    const replaced = key2.replace(regexp, '$1[^/]+$2');
+    if (replaced === key2) {
+      break;
+    }
+    key2 = replaced;
   }
 
   return regexMatch(key1, '^' + key2 + '$');
@@ -286,7 +302,6 @@ function ipMatch(ip1: string, ip2: string): boolean {
     return ip.cidrSubnet(ip2).contains(ip1);
   } else {
     if (!(ip.isV4Format(ip2) || ip.isV6Format(ip2))) {
-      console.log(ip2);
       throw new Error('invalid argument: ip2 in ipMatch() function is not an 
IP address.');
     }
     return ip.isEqual(ip1, ip2);
diff --git a/src/util/ip.ts b/src/util/ip.ts
index 6e22a2c..e093a70 100644
--- a/src/util/ip.ts
+++ b/src/util/ip.ts
@@ -135,10 +135,10 @@ export const ip = {
   },
 
   fromPrefixLen: function (prefixlen: number, family?: string): string {
-    family = _normalizeFamily(typeof family === 'string' ? family : 'ipv4');
-    if (prefixlen > 32) {
-      family = 'ipv6';
+    if (typeof family !== 'string') {
+      family = prefixlen > 32 ? 'ipv6' : 'ipv4';
     }
+    family = _normalizeFamily(family);
 
     let len = 4;
     if (family === 'ipv6') {
@@ -237,7 +237,14 @@ export const ip = {
     const addr = cidrParts[0];
     if (cidrParts.length !== 2) throw new Error('invalid CIDR subnet: ' + 
addr);
 
+    if (!ip.isV4Format(addr) && !ip.isV6Format(addr)) {
+      throw new Error('invalid CIDR subnet: ' + cidrString);
+    }
     const family = ip.isV6Format(addr) ? 'ipv6' : 'ipv4';
+    const maxPrefixLen = family === 'ipv6' ? 128 : 32;
+    if (!/^\d+$/.test(cidrParts[1]) || parseInt(cidrParts[1], 10) > 
maxPrefixLen) {
+      throw new Error('invalid CIDR subnet: ' + cidrString);
+    }
     const mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10), family);
 
     return ip.subnet(addr, mask);
diff --git a/test/util.test.ts b/test/util.test.ts
index c9b5ef8..44cdcc2 100644
--- a/test/util.test.ts
+++ b/test/util.test.ts
@@ -192,6 +192,33 @@ test('test ipMatchFunc - non-IP strings are rejected as 
ip1', () => {
   expect(() => util.ipMatchFunc('', '::1/128')).toThrow(Error);
 });
 
+test('test ipMatchFunc - out-of-range CIDR prefix is rejected', () => {
+  expect(() => util.ipMatchFunc('8.8.8.8', '192.168.2.0/33')).toThrow(/invalid 
CIDR/);
+  expect(() => util.ipMatchFunc('192.168.2.50', 
'192.168.2.0/33')).toThrow(/invalid CIDR/);
+  expect(() => util.ipMatchFunc('8.8.8.8', '192.168.2.0/64')).toThrow(/invalid 
CIDR/);
+  expect(() => util.ipMatchFunc('8.8.8.8', '192.168.2.0/96')).toThrow(/invalid 
CIDR/);
+  expect(() => util.ipMatchFunc('8.8.8.8', 
'192.168.2.0/128')).toThrow(/invalid CIDR/);
+  expect(() => util.ipMatchFunc('::1', '::1/129')).toThrow(/invalid CIDR/);
+  expect(() => util.ipMatchFunc('8.8.8.8', '192.168.2.0/')).toThrow(/invalid 
CIDR/);
+  expect(() => util.ipMatchFunc('8.8.8.8', '192.168.2.0/-1')).toThrow(/invalid 
CIDR/);
+  expect(() => util.ipMatchFunc('8.8.8.8', 
'192.168.2.0/24abc')).toThrow(/invalid CIDR/);
+  expect(() => util.ipMatchFunc('8.8.8.8', 'abc/24')).toThrow(/invalid CIDR/);
+  expect(util.ipMatchFunc('8.8.8.8', '0.0.0.0/0')).toEqual(true);
+  expect(util.ipMatchFunc('192.168.2.1', '192.168.2.1/32')).toEqual(true);
+  expect(util.ipMatchFunc('192.168.2.2', '192.168.2.1/32')).toEqual(false);
+  expect(util.ipMatchFunc('2001:db8::1', '2001:db8::/64')).toEqual(true);
+  expect(util.ipMatchFunc('2001:db9::1', '2001:db8::/64')).toEqual(false);
+});
+
+test('test keyMatch functions return on patterns with an empty token', () => {
+  expect(util.keyMatch2Func('/foo/bar', '/foo/:')).toEqual(false);
+  expect(util.keyMatch2Func('/foo/bar', '/:/bar')).toEqual(false);
+  expect(util.keyMatch3Func('/foo/bar', '/foo/{}')).toEqual(false);
+  expect(util.keyMatch3Func('/foo/bar', '/foo/{')).toEqual(false);
+  expect(util.keyMatch5Func('/foo/bar', '/foo/{}')).toEqual(false);
+  expect(util.keyMatch4Func('/foo/bar', '/foo/{')).toEqual(false);
+});
+
 test('test ip.isV4Format - octet range validation', () => {
   // Valid addresses
   expect(ip.isV4Format('0.0.0.0')).toEqual(true);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to