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]