From 6b1309a6b15b8bc4d3e257ca0cd34a14a56d694e Mon Sep 17 00:00:00 2001 From: Mustafa <104644957+Blacks-Army@users.noreply.github.com> Date: Mon, 13 Apr 2026 19:13:52 +0200 Subject: [PATCH 1/8] Exclude local/private/CGNAT IPs from COUNTRY=ALL and ASN=ALL/AS0 geo-blocking rules --- server/routers/badger/verifySession.ts | 57 ++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/server/routers/badger/verifySession.ts b/server/routers/badger/verifySession.ts index 8b57458..131a7d5 100644 --- a/server/routers/badger/verifySession.ts +++ b/server/routers/badger/verifySession.ts @@ -1027,7 +1027,11 @@ async function checkRules( isIpInCidr(clientIp, rule.value) ) { return rule.action as any; - } else if (clientIp && rule.match == "IP" && clientIp == rule.value) { + } else if ( + clientIp && + rule.match == "IP" && + clientIp == rule.value + ) { return rule.action as any; } else if ( path && @@ -1037,16 +1041,35 @@ async function checkRules( return rule.action as any; } else if ( clientIp && - rule.match == "COUNTRY" && - (await isIpInGeoIP(ipCC, rule.value)) + rule.match == "COUNTRY" ) { - return rule.action as any; + // COUNTRY=ALL should not affect local/private/CGNAT addresses. + if ( + rule.value.toUpperCase() === "ALL" && + isLocalOrCarrierGradeNatIp(clientIp) + ) { + continue; + } + + if (await isIpInGeoIP(ipCC, rule.value)) { + return rule.action as any; + } } else if ( clientIp && - rule.match == "ASN" && - (await isIpInAsn(ipAsn, rule.value)) + rule.match == "ASN" ) { - return rule.action as any; + // ASN=ALL/AS0 should not affect local/private/CGNAT addresses. + if ( + (rule.value.toUpperCase() === "ALL" || + rule.value.toUpperCase() === "AS0") && + isLocalOrCarrierGradeNatIp(clientIp) + ) { + continue; + } + + if (await isIpInAsn(ipAsn, rule.value)) { + return rule.action as any; + } } else if ( clientIp && rule.match == "REGION" && @@ -1208,6 +1231,26 @@ async function isIpInGeoIP( return ipCountryCode?.toUpperCase() === checkCountryCode.toUpperCase(); } +function isLocalOrCarrierGradeNatIp(ip: string): boolean { + const localAndCgnatCidrs = [ + "10.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16", + "100.64.0.0/10", + "127.0.0.0/8", + "169.254.0.0/16", + "::1/128", + "fc00::/7", + "fe80::/10" + ]; + + try { + return localAndCgnatCidrs.some((cidr) => isIpInCidr(ip, cidr)); + } catch { + return false; + } +} + async function isIpInAsn( ipAsn: number | undefined, checkAsn: string From afb823a7c0be7032cde919310a8fc7504756853c Mon Sep 17 00:00:00 2001 From: Owen Date: Thu, 14 May 2026 21:21:18 -0700 Subject: [PATCH 2/8] Remove funding --- .github/FUNDING.yml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index e3d0a44..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,3 +0,0 @@ -# These are supported funding model platforms - -github: [fosrl] From 5d6ca41f3a8fe9c73316dad0b578cc3836d01a2d Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Mon, 25 May 2026 21:44:59 -0700 Subject: [PATCH 3/8] update issue template --- .github/ISSUE_TEMPLATE/1.bug_report.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml index 41dbe7b..c945608 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -14,12 +14,13 @@ body: label: Environment description: Please fill out the relevant details below for your environment. value: | - - OS Type & Version: (e.g., Ubuntu 22.04) + - OS Type & Version: - Pangolin Version: + - Edition (Community or Enterprise): - Gerbil Version: - Traefik Version: - Newt Version: - - Olm Version: (if applicable) + - Client Version: validations: required: true From af0055560981088cd400bd4d1c5d0bed527cb872 Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Sun, 31 May 2026 20:25:46 -0700 Subject: [PATCH 4/8] update links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f82bb55..9fbb858 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ Take a look at the [quick install guide](https://docs.pangolin.net/manage/remote ## Licensing -Pangolin is dual licensed under the AGPL-3 and the [Fossorial Commercial License](https://pangolin.net/fcl.html). For inquiries about commercial licensing, please contact us at [contact@pangolin.net](mailto:contact@pangolin.net). +Pangolin is dual licensed under the AGPL-3 and the [Fossorial Commercial License](https://pangolin.net/fcl). For inquiries about commercial licensing, please contact us at [contact@pangolin.net](mailto:contact@pangolin.net). ## Contributions -Please see [CONTRIBUTING](./CONTRIBUTING.md) in the repository for guidelines and best practices. \ No newline at end of file +Please see [CONTRIBUTING](./CONTRIBUTING.md) in the repository for guidelines and best practices. From 9b5aa8e6585dceaa6f3b1ff9606882c3750c2405 Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 3 Jun 2026 15:34:08 -0700 Subject: [PATCH 5/8] Update to use new applyRules key --- server/routers/badger/verifySession.ts | 4 +++- server/routers/ws/verifySessionQueries.ts | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/server/routers/badger/verifySession.ts b/server/routers/badger/verifySession.ts index 131a7d5..bbe063c 100644 --- a/server/routers/badger/verifySession.ts +++ b/server/routers/badger/verifySession.ts @@ -138,6 +138,7 @@ export async function verifyResourceSession( password: ResourcePassword | null; headerAuth: ResourceHeaderAuth | null; headerAuthExtendedCompatibility: ResourceHeaderAuthExtendedCompatibility | null; + applyRules: boolean; org: Org; } | undefined = localCache.get(resourceCacheKey); @@ -169,6 +170,7 @@ export async function verifyResourceSession( const { resource, + applyRules, pincode, password, headerAuth, @@ -213,7 +215,7 @@ export async function verifyResourceSession( } // check the rules - if (resource.applyRules) { + if (applyRules) { const action = await checkRules( resource.resourceId, clientIp, diff --git a/server/routers/ws/verifySessionQueries.ts b/server/routers/ws/verifySessionQueries.ts index 2d526ad..09824ac 100644 --- a/server/routers/ws/verifySessionQueries.ts +++ b/server/routers/ws/verifySessionQueries.ts @@ -19,6 +19,7 @@ export type ResourceWithAuth = { password: ResourcePassword | null; headerAuth: ResourceHeaderAuth | null; headerAuthExtendedCompatibility: ResourceHeaderAuthExtendedCompatibility | null; + applyRules: boolean; org: Org; }; From ee2831fea0e0280722ca8ae0a07e51341169f0b1 Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 3 Jun 2026 16:25:12 -0700 Subject: [PATCH 6/8] Add email white list enabled and sso to breakout --- server/routers/badger/verifySession.ts | 33 +++++++++-------------- server/routers/ws/verifySessionQueries.ts | 2 ++ 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/server/routers/badger/verifySession.ts b/server/routers/badger/verifySession.ts index bbe063c..82055a3 100644 --- a/server/routers/badger/verifySession.ts +++ b/server/routers/badger/verifySession.ts @@ -139,6 +139,8 @@ export async function verifyResourceSession( headerAuth: ResourceHeaderAuth | null; headerAuthExtendedCompatibility: ResourceHeaderAuthExtendedCompatibility | null; applyRules: boolean; + sso: boolean; + emailWhitelistEnabled: boolean; org: Org; } | undefined = localCache.get(resourceCacheKey); @@ -171,6 +173,8 @@ export async function verifyResourceSession( const { resource, applyRules, + sso, + emailWhitelistEnabled, pincode, password, headerAuth, @@ -195,7 +199,7 @@ export async function verifyResourceSession( return notAllowed(res); } - const { sso, blockAccess } = resource; + const { blockAccess } = resource; if (blockAccess) { logger.debug("Resource blocked", host); @@ -270,7 +274,7 @@ export async function verifyResourceSession( !sso && !pincode && !password && - !resource.emailWhitelistEnabled && + !emailWhitelistEnabled && !headerAuth ) { logger.debug("Resource allowed because no auth"); @@ -453,7 +457,7 @@ export async function verifyResourceSession( !sso && !pincode && !password && - !resource.emailWhitelistEnabled && + !emailWhitelistEnabled && !headerAuthExtendedCompatibility?.extendedCompatibilityIsActivated ) { logRequestAudit( @@ -475,7 +479,7 @@ export async function verifyResourceSession( !sso && !pincode && !password && - !resource.emailWhitelistEnabled && + !emailWhitelistEnabled && !headerAuthExtendedCompatibility?.extendedCompatibilityIsActivated ) { logRequestAudit( @@ -614,10 +618,7 @@ export async function verifyResourceSession( return allowed(res); } - if ( - resource.emailWhitelistEnabled && - resourceSession.whitelistId - ) { + if (emailWhitelistEnabled && resourceSession.whitelistId) { logger.debug( "Resource allowed because whitelist session is valid" ); @@ -1029,11 +1030,7 @@ async function checkRules( isIpInCidr(clientIp, rule.value) ) { return rule.action as any; - } else if ( - clientIp && - rule.match == "IP" && - clientIp == rule.value - ) { + } else if (clientIp && rule.match == "IP" && clientIp == rule.value) { return rule.action as any; } else if ( path && @@ -1041,10 +1038,7 @@ async function checkRules( isPathAllowed(rule.value, path) ) { return rule.action as any; - } else if ( - clientIp && - rule.match == "COUNTRY" - ) { + } else if (clientIp && rule.match == "COUNTRY") { // COUNTRY=ALL should not affect local/private/CGNAT addresses. if ( rule.value.toUpperCase() === "ALL" && @@ -1056,10 +1050,7 @@ async function checkRules( if (await isIpInGeoIP(ipCC, rule.value)) { return rule.action as any; } - } else if ( - clientIp && - rule.match == "ASN" - ) { + } else if (clientIp && rule.match == "ASN") { // ASN=ALL/AS0 should not affect local/private/CGNAT addresses. if ( (rule.value.toUpperCase() === "ALL" || diff --git a/server/routers/ws/verifySessionQueries.ts b/server/routers/ws/verifySessionQueries.ts index 09824ac..eaa7022 100644 --- a/server/routers/ws/verifySessionQueries.ts +++ b/server/routers/ws/verifySessionQueries.ts @@ -20,6 +20,8 @@ export type ResourceWithAuth = { headerAuth: ResourceHeaderAuth | null; headerAuthExtendedCompatibility: ResourceHeaderAuthExtendedCompatibility | null; applyRules: boolean; + sso: boolean; + emailWhitelistEnabled: boolean; org: Org; }; From 1fad658cd9ff625ca65a446616f94495bca90951 Mon Sep 17 00:00:00 2001 From: Owen Date: Mon, 8 Jun 2026 20:56:53 -0700 Subject: [PATCH 7/8] Bring in line with 1.19 verifySession --- server/lib/types.ts | 7 ++++-- server/routers/badger/verifySession.ts | 33 +++++++++++++++++++------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/server/lib/types.ts b/server/lib/types.ts index 9799786..9c38d96 100644 --- a/server/lib/types.ts +++ b/server/lib/types.ts @@ -47,7 +47,7 @@ export type ResourceHeaderAuthExtendedCompatibility = { resourceId: number; headerAuthExtendedCompatibilityId: number; extendedCompatibilityIsActivated: boolean; -} +}; export type Org = { name: string; @@ -61,7 +61,7 @@ export type Org = { settingsLogRetentionDaysRequest: number; settingsLogRetentionDaysAccess: number; settingsLogRetentionDaysAction: number; -} +}; export type LoginPage = { loginPageId: number; @@ -103,6 +103,9 @@ export type ResourceSession = { accessTokenId: string | null; isRequestToken: boolean; userSessionId: string | null; + policyPasswordId: number | null; + policyPincodeId: number | null; + policyWhitelistId: number | null; issuedAt: number | null; }; diff --git a/server/routers/badger/verifySession.ts b/server/routers/badger/verifySession.ts index 82055a3..ee505dc 100644 --- a/server/routers/badger/verifySession.ts +++ b/server/routers/badger/verifySession.ts @@ -29,7 +29,8 @@ import { ResourceHeaderAuthExtendedCompatibility, ResourcePassword, ResourcePincode, - ResourceRule + ResourceRule, + ResourceSession } from "@server/lib/types"; import { verifyResourceAccessToken } from "@server/auth/verifyResourceAccessToken"; import { logRequestAudit } from "./logRequestAudit"; @@ -64,6 +65,7 @@ export type VerifyResourceSessionSchema = z.infer< >; type BasicUserData = { + userId: string; username: string; email: string | null; name: string | null; @@ -174,10 +176,10 @@ export async function verifyResourceSession( resource, applyRules, sso, - emailWhitelistEnabled, pincode, password, headerAuth, + emailWhitelistEnabled, headerAuthExtendedCompatibility } = resourceData; @@ -527,7 +529,8 @@ export async function verifyResourceSession( if (resourceSessionToken) { const sessionCacheKey = `session:${resourceSessionToken}`; - let resourceSession: any = localCache.get(sessionCacheKey); + let resourceSession: ResourceSession | null | undefined = + localCache.get(sessionCacheKey); if (!resourceSession) { const result = await validateResourceSessionToken( @@ -580,7 +583,11 @@ export async function verifyResourceSession( return notAllowed(res, redirectPath, resource.orgId); } - if (pincode && resourceSession.pincodeId) { + if ( + pincode && + (resourceSession.pincodeId || + resourceSession.policyPincodeId) + ) { logger.debug( "Resource allowed because pincode session is valid" ); @@ -599,7 +606,11 @@ export async function verifyResourceSession( return allowed(res); } - if (password && resourceSession.passwordId) { + if ( + password && + (resourceSession.passwordId || + resourceSession.policyPasswordId) + ) { logger.debug( "Resource allowed because password session is valid" ); @@ -618,7 +629,11 @@ export async function verifyResourceSession( return allowed(res); } - if (emailWhitelistEnabled && resourceSession.whitelistId) { + if ( + emailWhitelistEnabled && + (resourceSession.whitelistId || + resourceSession.policyWhitelistId) + ) { logger.debug( "Resource allowed because whitelist session is valid" ); @@ -650,7 +665,7 @@ export async function verifyResourceSession( orgId: resource.orgId, location: ipCC, apiKey: { - name: resourceSession.accessTokenTitle, + name: null, apiKeyId: resourceSession.accessTokenId } }, @@ -695,7 +710,7 @@ export async function verifyResourceSession( location: ipCC, user: { username: allowedUserData.username, - userId: resourceSession.userId + userId: allowedUserData.userId } }, parsedBody.data @@ -960,6 +975,7 @@ async function isUserAllowedToAccessResource( ); if (roleResourceAccess && roleResourceAccess.length > 0) { return { + userId: user.userId, username: user.username, email: user.email, name: user.name, @@ -980,6 +996,7 @@ async function isUserAllowedToAccessResource( if (userResourceAccess) { return { + userId: user.userId, username: user.username, email: user.email, name: user.name, From e3a99fe059a0f9074f23541437123d6c1f86ff2f Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 10 Jun 2026 17:42:12 -0700 Subject: [PATCH 8/8] Allow null --- server/routers/badger/verifySession.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/routers/badger/verifySession.ts b/server/routers/badger/verifySession.ts index ee505dc..4a7ae67 100644 --- a/server/routers/badger/verifySession.ts +++ b/server/routers/badger/verifySession.ts @@ -140,9 +140,9 @@ export async function verifyResourceSession( password: ResourcePassword | null; headerAuth: ResourceHeaderAuth | null; headerAuthExtendedCompatibility: ResourceHeaderAuthExtendedCompatibility | null; - applyRules: boolean; - sso: boolean; - emailWhitelistEnabled: boolean; + applyRules: boolean | null; + sso: boolean | null; + emailWhitelistEnabled: boolean | null; org: Org; } | undefined = localCache.get(resourceCacheKey);