From 37c30461db07452964ab55fb2154647e9bd6519a Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 22 Oct 2025 15:18:55 -0700 Subject: [PATCH 01/46] chore: add .smarttomcat dir to gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d6827f60..de33b11b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ examples/examples.iml .DS_Store .classpath .project -.factorypath \ No newline at end of file +.factorypath +.smarttomcat \ No newline at end of file From 1d6f336b1ab622b021f6805577665aad9cdb624b Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 22 Oct 2025 15:19:53 -0700 Subject: [PATCH 02/46] feat: add is_sensitive_route to activities --- src/main/java/com/perimeterx/models/PXContext.java | 7 +++++++ .../models/activities/CommonActivityDetails.java | 5 ++++- .../java/com/perimeterx/models/httpmodels/Additional.java | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/perimeterx/models/PXContext.java b/src/main/java/com/perimeterx/models/PXContext.java index 90b7c38c..ca812caf 100644 --- a/src/main/java/com/perimeterx/models/PXContext.java +++ b/src/main/java/com/perimeterx/models/PXContext.java @@ -232,6 +232,7 @@ public class PXContext { private String pxhdDomain; private String pxCtsCookie; private long enforcerStartTime; + private boolean isSensitiveRequest; /** * The cookie key used to decrypt the cookie @@ -291,6 +292,7 @@ private void postInitContext(final HttpServletRequest request, PXConfiguration p String protocolDetails[] = request.getProtocol().split("/"); this.httpVersion = protocolDetails.length > 1 ? protocolDetails[1] : StringUtils.EMPTY; + this.isSensitiveRequest = determineIsSensitiveRequest(); CustomParametersProvider customParametersProvider = pxConfiguration.getCustomParametersProvider(); Function customParametersExtraction = pxConfiguration.getCustomParametersExtraction(); @@ -310,7 +312,12 @@ private IPXLogger getLogger(){ boolean isLoggerHeaderRequest = requestLoggerAuthToken!=null && this.getPxConfiguration().getLoggerAuthToken().equals(requestLoggerAuthToken); return pxConfiguration.getLoggerFactory().getRequestContextLogger(isLoggerHeaderRequest); } + public boolean isSensitiveRequest() { + return this.isSensitiveRequest; + } + + private boolean determineIsSensitiveRequest() { return this.isContainCredentialsIntelligence() || checkSensitiveRoute(pxConfiguration.getSensitiveRoutes(), servletPath) || checkSensitiveRouteRegex(pxConfiguration.getSensitiveRoutesRegex(), servletPath) diff --git a/src/main/java/com/perimeterx/models/activities/CommonActivityDetails.java b/src/main/java/com/perimeterx/models/activities/CommonActivityDetails.java index c5baf184..e66da0d2 100644 --- a/src/main/java/com/perimeterx/models/activities/CommonActivityDetails.java +++ b/src/main/java/com/perimeterx/models/activities/CommonActivityDetails.java @@ -59,6 +59,9 @@ public class CommonActivityDetails implements ActivityDetails { @JsonProperty("cross_tab_session") public String pxCtsCookie; + @JsonProperty("is_sensitive_route") + public Boolean isSensitiveRoute; + public CommonActivityDetails(PXContext context) { final LoginData loginData = context.getLoginData(); @@ -85,6 +88,6 @@ public CommonActivityDetails(PXContext context) { this.riskStartTime = additional.riskStartTime; this.enforcerStartTime = additional.enforcerStartTime; this.pxCtsCookie = additional.pxCtsCookie; - + this.isSensitiveRoute = additional.isSensitiveRoute; } } diff --git a/src/main/java/com/perimeterx/models/httpmodels/Additional.java b/src/main/java/com/perimeterx/models/httpmodels/Additional.java index 2c4df51c..228d4a6d 100644 --- a/src/main/java/com/perimeterx/models/httpmodels/Additional.java +++ b/src/main/java/com/perimeterx/models/httpmodels/Additional.java @@ -93,6 +93,9 @@ public class Additional { @JsonProperty("cross_tab_session") public String pxCtsCookie; + @JsonProperty("is_sensitive_route") + public Boolean isSensitiveRoute; + public static Additional fromContext(PXContext ctx) { Additional additional = new Additional(); additional.pxCookie = ctx.getRiskCookie(); @@ -114,6 +117,7 @@ public static Additional fromContext(PXContext ctx) { additional.enforcerStartTime = ctx.getEnforcerStartTime(); additional.riskStartTime = new Date().getTime(); additional.pxCtsCookie = ctx.getPxCtsCookie(); + additional.isSensitiveRoute = ctx.isSensitiveRequest(); setLoginCredentials(ctx, additional); From 235a85bb36152afce7b151cbc796a1d00d8b4db0 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 22 Oct 2025 15:32:07 -0700 Subject: [PATCH 03/46] feat: added support for px_logger_severity in example --- web/src/main/java/com/web/Config.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/src/main/java/com/web/Config.java b/web/src/main/java/com/web/Config.java index 1d7333f6..0dc57323 100644 --- a/web/src/main/java/com/web/Config.java +++ b/web/src/main/java/com/web/Config.java @@ -6,6 +6,7 @@ import com.perimeterx.models.configuration.PXConfiguration; import com.perimeterx.models.configuration.credentialsIntelligenceconfig.CILoginMap; import com.perimeterx.models.risk.CustomParameters; +import com.perimeterx.utils.logger.LoggerSeverity; import org.json.JSONArray; import org.json.JSONObject; @@ -153,6 +154,12 @@ public PXConfiguration getPxConfiguration() { case "px_login_successful_status": builder.loginResponseValidationStatusCode(extractStatusCode(key)); break; + case "px_logger_severity": + LoggerSeverity loggerSeverity = LoggerSeverity.DEBUG.jsonName().equals(enforcerConfig.getString(key)) ? + LoggerSeverity.DEBUG : LoggerSeverity.NONE.jsonName().equals(enforcerConfig.getString(key)) ? + LoggerSeverity.NONE : LoggerSeverity.ERROR; + PXConfiguration.setPxLoggerSeverity(loggerSeverity); + break; case "px_user_agent_max_length": case "px_risk_cookie_max_length": case "px_risk_cookie_max_iterations": From c420fda315c61fc247853640af8da3e3acab0f47 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 22 Oct 2025 15:32:47 -0700 Subject: [PATCH 04/46] chore: very minor refactoring fixes --- src/main/java/com/perimeterx/models/PXContext.java | 2 +- src/main/java/com/perimeterx/utils/logger/LoggerFactory.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/perimeterx/models/PXContext.java b/src/main/java/com/perimeterx/models/PXContext.java index ca812caf..9752eac2 100644 --- a/src/main/java/com/perimeterx/models/PXContext.java +++ b/src/main/java/com/perimeterx/models/PXContext.java @@ -290,7 +290,7 @@ private void postInitContext(final HttpServletRequest request, PXConfiguration p this.enforcerErrorReasonInfo = new EnforcerErrorReasonInfo(); this.sensitiveHeaders = pxConfiguration.getSensitiveHeaders(); - String protocolDetails[] = request.getProtocol().split("/"); + String[] protocolDetails = request.getProtocol().split("/"); this.httpVersion = protocolDetails.length > 1 ? protocolDetails[1] : StringUtils.EMPTY; this.isSensitiveRequest = determineIsSensitiveRequest(); diff --git a/src/main/java/com/perimeterx/utils/logger/LoggerFactory.java b/src/main/java/com/perimeterx/utils/logger/LoggerFactory.java index 42b400c3..26ed9eb3 100644 --- a/src/main/java/com/perimeterx/utils/logger/LoggerFactory.java +++ b/src/main/java/com/perimeterx/utils/logger/LoggerFactory.java @@ -9,7 +9,7 @@ public IPXLogger getRequestContextLogger(boolean isMemoryEnabled) { if (pxLoggerSeverity == null) { return new Slf4JLogger(isMemoryEnabled); } else { - return new ConsoleLogger(pxLoggerSeverity,isMemoryEnabled); + return new ConsoleLogger(pxLoggerSeverity, isMemoryEnabled); } } public IPXLogger getRequestContextLogger() { From 516aa9ae436ee7b977ca3960735a8098ed3132a0 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 22 Oct 2025 15:48:06 -0700 Subject: [PATCH 05/46] chore: updating dependencies --- pom.xml | 20 ++++++++++---------- web/pom.xml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index e32fe360..69125d25 100644 --- a/pom.xml +++ b/pom.xml @@ -132,19 +132,19 @@ com.fasterxml.jackson.core jackson-databind - 2.11.4 + 2.17.2 com.fasterxml.jackson.core jackson-annotations - 2.10.2 + 2.17.2 commons-io commons-io - 2.8.0 + 2.14.0 @@ -156,7 +156,7 @@ org.apache.commons commons-lang3 - 3.12.0 + 3.18.0 @@ -168,19 +168,19 @@ org.slf4j slf4j-api - 1.7.30 + 1.7.36 org.apache.httpcomponents httpasyncclient - 4.1.4 + 4.1.5 org.apache.httpcomponents httpclient - 4.5.13 + 4.5.14 @@ -207,14 +207,14 @@ org.springframework spring-test - 4.3.1.RELEASE + 4.3.30.RELEASE test org.springframework spring-web - 4.3.1.RELEASE + 4.3.30.RELEASE test @@ -228,7 +228,7 @@ com.google.code.gson gson - 2.8.6 + 2.10.1 compile diff --git a/web/pom.xml b/web/pom.xml index 404ffa14..a0585a32 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -31,7 +31,7 @@ org.slf4j slf4j-api - 1.7.25 + 1.7.36 org.slf4j From 4061c97fc77cc1464d5ecb86bf004dfcda12abab Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 22 Oct 2025 16:00:13 -0700 Subject: [PATCH 06/46] chore: alphabetized px_metadata supported features --- px_metadata.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/px_metadata.json b/px_metadata.json index d4dacd1d..041b8c7c 100644 --- a/px_metadata.json +++ b/px_metadata.json @@ -2,41 +2,41 @@ "version": "6.15.1", "supported_features": [ "advanced_blocking_response", - "bypass_monitor_header", + "batched_activities", "block_activity", "block_page_captcha", + "block_page_hard_block", "block_page_js_challenge", "block_page_rate_limit", + "bypass_monitor_header", "client_ip_extraction", "cookie_v3", "credentials_intelligence", "css_ref", + "custom_cookie_header", "custom_logo", "custom_parameters", "custom_proxy", "custom_sensitive_request", "enforced_routes", - "logger", + "enforcer_error", "filter_by_extension", "first_party", + "header_based_logger", "js_ref", + "logger", "mobile_support", "module_enable", "module_mode", "monitored_routes", "page_requested_activity", "pxde", - "vid_extraction", + "pxhd", "risk_api", - "custom_cookie_header", + "sensitive_headers", "sensitive_routes", "telemetry_command", - "enforcer_error", - "pxhd", - "batched_activities", - "sensitive_headers", - "block_page_hard_block", - "header_based_logger" + "vid_extraction" ], "excluded_tests": [ "test_pxde_extraction_(s2s|unverified|verified)", From 38842916ffad05ca6fbae24934e73f1a87e60ba6 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 22 Oct 2025 19:03:45 -0700 Subject: [PATCH 07/46] fix: update module mode to resolve unit test failures --- .../models/configuration/ModuleMode.java | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/perimeterx/models/configuration/ModuleMode.java b/src/main/java/com/perimeterx/models/configuration/ModuleMode.java index ef121579..901b0761 100644 --- a/src/main/java/com/perimeterx/models/configuration/ModuleMode.java +++ b/src/main/java/com/perimeterx/models/configuration/ModuleMode.java @@ -10,13 +10,11 @@ * Created by nitzangoldfeder on 26/06/2017. */ public enum ModuleMode { - MONITOR(0), BLOCKING(1); - private int value; - - private static Map namesMap = new HashMap<>(2); + private final int value; + private static final Map namesMap = new HashMap<>(2); static { namesMap.put(0, MONITOR); namesMap.put(1, BLOCKING); @@ -27,26 +25,12 @@ public static ModuleMode forValue(Integer value) { return namesMap.get(value); } - @JsonValue - public Integer toValue() { - for (Map.Entry entry : namesMap.entrySet()) { - if (entry.getValue() == this) - return entry.getKey(); - } - return 0; - } - - ModuleMode(int value) { - this.value = value; - } - @JsonValue public int getValue() { return this.value; } - @JsonCreator - public void setValue(int value) { + ModuleMode(int value) { this.value = value; } } From 7f3d4816bb0277019bd59d120f7347a80729a226 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 23 Oct 2025 09:12:42 -0700 Subject: [PATCH 08/46] chore: updating gha checkout, setup-node actions --- .github/workflows/cd.yaml | 10 +++++----- .github/workflows/ci_e2e.yaml | 14 +++++++------- .github/workflows/ci_verify_version.yaml | 4 ++-- .github/workflows/docs_enforcement.yml | 6 +++--- .github/workflows/fuzzer.yaml | 14 +++++++------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml index 830f54a6..e99e0760 100644 --- a/.github/workflows/cd.yaml +++ b/.github/workflows/cd.yaml @@ -11,11 +11,11 @@ jobs: version: ${{ steps.version.outputs.value }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: '18.x' + node-version: '22.x' - name: Get package version id: version run: echo "value=$(node -p -e "require('./px_metadata.json').version")" >> "$GITHUB_OUTPUT" @@ -28,7 +28,7 @@ jobs: contents: write steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - run: gh release create v${{ needs.extract_version.outputs.version }} --generate-notes -t "Version ${{ needs.extract_version.outputs.version }}" env: GITHUB_TOKEN: ${{ github.TOKEN }} @@ -42,7 +42,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up JDK 8 uses: actions/setup-java@v3 diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index f3e6a9bf..91e222fd 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -12,11 +12,11 @@ jobs: supported-features: ${{ steps.supported-features.outputs.value }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: '20.x' + node-version: '22.x' - name: extract supported features id: supported-features run: echo "value=$(node -p -e "require('./px_metadata.json').supported_features?.join(' or ') || ''")" >> "$GITHUB_OUTPUT" @@ -37,7 +37,7 @@ jobs: steps: - name: Checkout Repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up Docker uses: docker/setup-buildx-action@v3 @@ -55,7 +55,7 @@ jobs: version: '3.14.1' - name: Clone helm charts repo - mock-collector - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} @@ -64,7 +64,7 @@ jobs: - name: Clone helm charts repo - enforcer-tests - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} @@ -73,7 +73,7 @@ jobs: - name: Clone helm charts repo - sample-site - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} diff --git a/.github/workflows/ci_verify_version.yaml b/.github/workflows/ci_verify_version.yaml index 9fcd468a..64a18a71 100644 --- a/.github/workflows/ci_verify_version.yaml +++ b/.github/workflows/ci_verify_version.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - ${{ github.base_ref }} - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.base_ref }} @@ -18,7 +18,7 @@ jobs: run: echo "project=$( mvn help:evaluate -Dexpression=project.version -q -DforceStdout )" >> "$GITHUB_OUTPUT" - name: Checkout code - current commit - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Get current SDK versions id: new-version diff --git a/.github/workflows/docs_enforcement.yml b/.github/workflows/docs_enforcement.yml index 213c85c7..22fa0a2c 100644 --- a/.github/workflows/docs_enforcement.yml +++ b/.github/workflows/docs_enforcement.yml @@ -16,12 +16,12 @@ jobs: version: ${{ steps.version.outputs.value }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: '22' + node-version: '22.x' - name: Get package version id: version diff --git a/.github/workflows/fuzzer.yaml b/.github/workflows/fuzzer.yaml index 4c939349..59c81c80 100644 --- a/.github/workflows/fuzzer.yaml +++ b/.github/workflows/fuzzer.yaml @@ -12,11 +12,11 @@ jobs: supported-features: ${{ steps.version.outputs.value }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: 'latest' + node-version: '22.x' - name: Get package version id: version run: echo "value=$(node -p -e "require('./px_metadata.json').version")" >> "$GITHUB_OUTPUT" @@ -42,7 +42,7 @@ jobs: steps: - name: Checkout Repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up Docker uses: docker/setup-buildx-action@v3 @@ -60,7 +60,7 @@ jobs: version: '3.14.2' - name: Clone helm charts repo - mock-collector - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} @@ -68,7 +68,7 @@ jobs: path: ./deploy_charts/mock-collector - name: Clone helm charts repo - fuzzer - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} @@ -76,7 +76,7 @@ jobs: path: ./deploy_charts/fuzzer - name: Clone helm charts repo - sample-site - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} From 23ed5c18871bcacb98f28419e369ce40471174c5 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 23 Oct 2025 09:23:57 -0700 Subject: [PATCH 09/46] update: fuzzer, mock collector, specs test tags --- .github/workflows/ci_e2e.yaml | 4 ++-- .github/workflows/fuzzer.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index 91e222fd..71388002 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -25,9 +25,9 @@ jobs: CI: name: "E2E tests" env: - MOCK_COLLECTOR_IMAGE_TAG: 1.3.5 + MOCK_COLLECTOR_IMAGE_TAG: 2.0.5 SAMPLE_SITE_IMAGE_TAG: 1.0.0 - ENFORCER_SPEC_TESTS_IMAGE_TAG: 1.8.1 + ENFORCER_SPEC_TESTS_IMAGE_TAG: 1.21.0 runs-on: ubuntu-latest timeout-minutes: 60 diff --git a/.github/workflows/fuzzer.yaml b/.github/workflows/fuzzer.yaml index 59c81c80..b5eae821 100644 --- a/.github/workflows/fuzzer.yaml +++ b/.github/workflows/fuzzer.yaml @@ -25,8 +25,8 @@ jobs: Fuzzing: name: "Fuzzing Test" env: - MOCK_COLLECTOR_IMAGE_TAG: 1.3.6 - FUZZER_TAG: 1.0.4 + MOCK_COLLECTOR_IMAGE_TAG: 2.0.5 + FUZZER_TAG: 1.1.0 SAMPLE_SITE_IMAGE_TAG: 1.0.0 ENFORCER_TAG: ${{ needs.extract_version.outputs.version }} From 434732bda13562483434da073a29acc941f8dd40 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 23 Oct 2025 10:31:38 -0700 Subject: [PATCH 10/46] update: helm chart versions --- .github/workflows/ci_e2e.yaml | 10 +++++++--- .github/workflows/fuzzer.yaml | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index 71388002..6ffa8f0f 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -59,7 +59,7 @@ jobs: with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} - ref: mock-collector-0.1.1 + ref: mock-collector-0.1.2 path: ./deploy_charts/mock-collector @@ -68,7 +68,7 @@ jobs: with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} - ref: enforcer-spec-tests-0.7.1 + ref: enforcer-spec-tests-0.9.1 path: ./deploy_charts/enforcer-spec-tests @@ -77,7 +77,7 @@ jobs: with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} - ref: sample-site-0.5.0 + ref: sample-site-0.6.1 path: ./deploy_charts/sample-site - name: Set up Google Cloud SDK @@ -101,6 +101,7 @@ jobs: helm install mock-collector ./deploy_charts/mock-collector/charts/mock-collector \ --set image.repository=localhost:5001/mock-collector \ --set image.tag=$MOCK_COLLECTOR_IMAGE_TAG \ + --set authToken=${{ secrets.PX_AUTH_TOKEN }} \ --set imagePullPolicy=Always --wait - name: set secrets in enforcer config @@ -118,6 +119,9 @@ jobs: helm install java-enforcer ./deploy_charts/sample-site/charts/sample-site \ -f ./ci_files/enforcer-values.yaml \ --set image.name=localhost:5001/java-enforcer-sample-site \ + --set appId=${{ secrets.PX_APP_ID }} \ + --set cookieSecret=${{ secrets.TEST_COOKIE_SECRET }} \ + --set authToken=${{ secrets.PX_AUTH_TOKEN }} \ --set image.tag=$SAMPLE_SITE_IMAGE_TAG \ --set-file enforcerConfig.content=/tmp/enforcer-config.json \ --wait diff --git a/.github/workflows/fuzzer.yaml b/.github/workflows/fuzzer.yaml index b5eae821..f66b6788 100644 --- a/.github/workflows/fuzzer.yaml +++ b/.github/workflows/fuzzer.yaml @@ -64,7 +64,7 @@ jobs: with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} - ref: mock-collector-0.1.1 + ref: mock-collector-0.1.2 path: ./deploy_charts/mock-collector - name: Clone helm charts repo - fuzzer @@ -72,7 +72,7 @@ jobs: with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} - ref: fuzzer-0.2.0 + ref: fuzzer-0.3.1 path: ./deploy_charts/fuzzer - name: Clone helm charts repo - sample-site @@ -80,7 +80,7 @@ jobs: with: repository: PerimeterX/connect-helm-charts token: ${{ secrets.CONNECT_PULL_TOKEN }} - ref: sample-site-0.5.0 + ref: sample-site-0.6.1 path: ./deploy_charts/sample-site - name: Set up Google Cloud SDK @@ -104,6 +104,7 @@ jobs: helm install mock-collector ./deploy_charts/mock-collector/charts/mock-collector \ --set image.repository=localhost:5001/mock-collector \ --set image.tag=$MOCK_COLLECTOR_IMAGE_TAG \ + --set authToken=${{ secrets.PX_AUTH_TOKEN }} \ --set imagePullPolicy=Always --wait - name: set secrets in enforcer config @@ -122,6 +123,9 @@ jobs: -f ./ci_files/enforcer-values.yaml \ --set image.name=localhost:5001/java-enforcer-sample-site \ --set image.tag=$SAMPLE_SITE_IMAGE_TAG \ + --set appId=${{ secrets.PX_APP_ID }} \ + --set cookieSecret=${{ secrets.TEST_COOKIE_SECRET }} \ + --set authToken=${{ secrets.PX_AUTH_TOKEN }} \ --set-file enforcerConfig.content=/tmp/enforcer-config.json \ --wait From ce64628f331c4c05c1053d2eb1ef33808ba47a44 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 23 Oct 2025 10:40:18 -0700 Subject: [PATCH 11/46] fix: adding enforcerConfigJsonContent to e2e test run --- .github/workflows/ci_e2e.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index 6ffa8f0f..d45a3566 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -141,6 +141,7 @@ jobs: --set authToken="${{ secrets.PX_AUTH_TOKEN }}" \ --set appId=${{ secrets.PX_APP_ID }} \ --set-file enforcerMetadataContent=./px_metadata.json \ + --set-file enforcerConfigJsonContent=/tmp/enforcer-config.json \ -f ./ci_files/spec-tests-values.yaml \ --wait \ --timeout 60m0s \ From 0c6e4cfda685121cc011f0486c96460dd11208f9 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 23 Oct 2025 11:21:09 -0700 Subject: [PATCH 12/46] feat: add request ID to telemetry activity --- .../api/activities/DefaultActivityHandler.java | 2 +- .../activities/EnforcerTelemetryActivityDetails.java | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/perimeterx/api/activities/DefaultActivityHandler.java b/src/main/java/com/perimeterx/api/activities/DefaultActivityHandler.java index 045341d2..53bd4d0b 100644 --- a/src/main/java/com/perimeterx/api/activities/DefaultActivityHandler.java +++ b/src/main/java/com/perimeterx/api/activities/DefaultActivityHandler.java @@ -48,7 +48,7 @@ public void handlePageRequestedActivity(PXContext context) throws PXException { @Override public void handleEnforcerTelemetryActivity(PXConfiguration pxConfiguration, UpdateReason updateReason, PXContext context) { try { - EnforcerTelemetryActivityDetails details = new EnforcerTelemetryActivityDetails(pxConfiguration, updateReason); + EnforcerTelemetryActivityDetails details = new EnforcerTelemetryActivityDetails(pxConfiguration, context, updateReason); EnforcerTelemetry enforcerTelemetry = new EnforcerTelemetry("enforcer_telemetry", pxConfiguration.getAppId(), details); this.client.sendEnforcerTelemetry(enforcerTelemetry, context); } catch (Exception e) { diff --git a/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java b/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java index 3117a07e..9e5e6d6c 100644 --- a/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java +++ b/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java @@ -3,11 +3,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.google.gson.Gson; import com.google.gson.JsonIOException; +import com.perimeterx.models.PXContext; import com.perimeterx.models.configuration.PXConfiguration; import com.perimeterx.utils.Constants; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.UUID; /** * Created by nitzangoldfeder on 29/10/2017. @@ -24,11 +26,14 @@ public class EnforcerTelemetryActivityDetails implements ActivityDetails { private String nodeName; @JsonProperty("update_reason") private UpdateReason updateReason; + @JsonProperty + private UUID requestId; - public EnforcerTelemetryActivityDetails(PXConfiguration pxConfiguration, UpdateReason updateReason) { + public EnforcerTelemetryActivityDetails(PXConfiguration pxConfiguration, PXContext context, UpdateReason updateReason) { this.moduleVersion = Constants.SDK_VERSION; this.osName = System.getProperty("os.name"); this.updateReason = updateReason; + this.requestId = context.getRequestId(); try { this.nodeName = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { @@ -59,4 +64,8 @@ public String getOsName() { public String getNodeName() { return nodeName; } + + public UUID getRequestId() { + return requestId; + } } From 9b3817f34c71c78212229a964426525af02c6edd Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 23 Oct 2025 11:45:59 -0700 Subject: [PATCH 13/46] fix: redacting sensitive fields in telemetry, changing telemetry config structure --- .../activities/EnforcerTelemetryActivityDetails.java | 12 ++++++++++-- .../models/configuration/PXConfiguration.java | 11 ++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java b/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java index 9e5e6d6c..ae1b54a3 100644 --- a/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java +++ b/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java @@ -1,6 +1,8 @@ package com.perimeterx.models.activities; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.JsonIOException; import com.perimeterx.models.PXContext; @@ -9,6 +11,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.Properties; import java.util.UUID; /** @@ -43,8 +46,13 @@ public EnforcerTelemetryActivityDetails(PXConfiguration pxConfiguration, PXConte try { Gson gson = new Gson(); String pxConfigJson = gson.toJson(pxConfiguration.getTelemetryConfig()); - this.enforcerConfigs = pxConfigJson; - } catch (JsonIOException e) { + ObjectMapper mapper = new ObjectMapper(); + Properties p = new Properties(); + p.put("active_config", pxConfigJson); + p.put("static_config", pxConfigJson); + p.put("remote_config", "{}"); // remote config not supported + this.enforcerConfigs = mapper.writeValueAsString(p); + } catch (JsonIOException | JsonProcessingException e) { this.enforcerConfigs = "Could not retrieve pxConfiguration"; } } diff --git a/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java b/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java index 1f0665d1..678e1f80 100644 --- a/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java +++ b/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java @@ -312,7 +312,16 @@ public static void setPxLoggerSeverity(LoggerSeverity severity) { * @return Configuration Object clone without cookieKey and authToken **/ public PXConfiguration getTelemetryConfig() { - return this.toBuilder().clearCookieKeys().authToken(null).build(); + int trailingChars = 4; + String redactedPrefix = "***REDACTED***"; + String redactedAuthToken = redactedPrefix.concat(this.authToken.substring(this.authToken.length() - trailingChars)); + List redactedCookieKeys = this.cookieKeys.stream().map((key) -> "***REDACTED***".concat(key.substring(key.length() - trailingChars))).collect(Collectors.toList()); + String redactedLoggerAuthToken = this.loggerAuthToken.isEmpty() ? null : redactedPrefix.concat(this.loggerAuthToken.substring(this.loggerAuthToken.length() - trailingChars)); + return this.toBuilder() + .authToken(redactedAuthToken) + .cookieKeys(redactedCookieKeys) + .loggerAuthToken(redactedLoggerAuthToken) + .build(); } public void disableModule() { From 53e63af7633a09f73457cfefa51d7e136157afad Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 23 Oct 2025 11:54:00 -0700 Subject: [PATCH 14/46] fix: compilation issues re: request id in telemetry --- .../com/perimeterx/api/activities/BufferedActivityHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/perimeterx/api/activities/BufferedActivityHandler.java b/src/main/java/com/perimeterx/api/activities/BufferedActivityHandler.java index fb6c006e..d704f37c 100644 --- a/src/main/java/com/perimeterx/api/activities/BufferedActivityHandler.java +++ b/src/main/java/com/perimeterx/api/activities/BufferedActivityHandler.java @@ -57,7 +57,7 @@ public void handlePageRequestedActivity(PXContext context) throws PXException { @Override public void handleEnforcerTelemetryActivity(PXConfiguration pxConfig, UpdateReason updateReason, PXContext context) { try { - EnforcerTelemetryActivityDetails details = new EnforcerTelemetryActivityDetails(pxConfig, updateReason); + EnforcerTelemetryActivityDetails details = new EnforcerTelemetryActivityDetails(pxConfig, context, updateReason); EnforcerTelemetry enforcerTelemetry = new EnforcerTelemetry("enforcer_telemetry", pxConfig.getAppId(), details); this.client.sendEnforcerTelemetry(enforcerTelemetry, context); } catch (IOException e) { From b3cbab4b847536a39f50d9855cff4433f4288ae2 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Fri, 24 Oct 2025 14:38:09 -0700 Subject: [PATCH 15/46] wip --- .../EnforcerTelemetryActivityDetails.java | 100 +++++++++++++++--- .../models/configuration/PXConfiguration.java | 51 +++++++-- 2 files changed, 125 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java b/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java index ae1b54a3..c2f5a576 100644 --- a/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java +++ b/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java @@ -1,9 +1,7 @@ package com.perimeterx.models.activities; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.google.gson.JsonIOException; import com.perimeterx.models.PXContext; import com.perimeterx.models.configuration.PXConfiguration; @@ -11,7 +9,6 @@ import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.Properties; import java.util.UUID; /** @@ -22,14 +19,14 @@ public class EnforcerTelemetryActivityDetails implements ActivityDetails { @JsonProperty("module_version") private String moduleVersion; @JsonProperty("enforcer_configs") - private String enforcerConfigs; + private TelemetryConfiguration enforcerConfigs; @JsonProperty("os_name") private String osName; @JsonProperty("node_name") private String nodeName; @JsonProperty("update_reason") private UpdateReason updateReason; - @JsonProperty + @JsonProperty("request_id") private UUID requestId; public EnforcerTelemetryActivityDetails(PXConfiguration pxConfiguration, PXContext context, UpdateReason updateReason) { @@ -44,16 +41,13 @@ public EnforcerTelemetryActivityDetails(PXConfiguration pxConfiguration, PXConte } try { - Gson gson = new Gson(); - String pxConfigJson = gson.toJson(pxConfiguration.getTelemetryConfig()); - ObjectMapper mapper = new ObjectMapper(); - Properties p = new Properties(); - p.put("active_config", pxConfigJson); - p.put("static_config", pxConfigJson); - p.put("remote_config", "{}"); // remote config not supported - this.enforcerConfigs = mapper.writeValueAsString(p); - } catch (JsonIOException | JsonProcessingException e) { - this.enforcerConfigs = "Could not retrieve pxConfiguration"; + PXConfiguration config = pxConfiguration.getTelemetryConfig(); + enforcerConfigs = new TelemetryConfiguration(); + enforcerConfigs.activeConfig = config; + enforcerConfigs.staticConfig = config; + enforcerConfigs.remoteConfig = null; // remote config not supported + } catch (JsonIOException e) { + enforcerConfigs = null; } } @@ -61,7 +55,7 @@ public String getModuleVersion() { return moduleVersion; } - public String getEnforcerConfigs() { + public TelemetryConfiguration getEnforcerConfigs() { return enforcerConfigs; } @@ -77,3 +71,75 @@ public UUID getRequestId() { return requestId; } } + +class TelemetryConfiguration { + @JsonProperty("active_config") + @JsonIgnoreProperties({ + "customParametersProvider", + "blockHandler", + "customLoginResponseValidator", + "credentialsCustomExtractor", + "customIsSensitiveRequest", + "customParametersExtraction", + "filterByCustomFunction", + "loggerFactory", + "telemetryConfig", + "reverseProxyInstance", + "ipxHttpClientInstance", + "ipxhttpClientInstance", + "IPXHttpClientInstance", + "pxClientInstance", + "PXClientInstance", + "pxclientInstance", + "httpClient", + "pxClient", + "pxReverseProxy" + }) + public PXConfiguration activeConfig; + @JsonProperty("static_config") + @JsonIgnoreProperties({ + "customParametersProvider", + "blockHandler", + "customLoginResponseValidator", + "credentialsCustomExtractor", + "customIsSensitiveRequest", + "customParametersExtraction", + "filterByCustomFunction", + "loggerFactory", + "telemetryConfig", + "reverseProxyInstance", + "ipxHttpClientInstance", + "ipxhttpClientInstance", + "IPXHttpClientInstance", + "pxClientInstance", + "PXClientInstance", + "pxclientInstance", + "httpClient", + "pxClient", + "pxReverseProxy" + }) + public PXConfiguration staticConfig; + @JsonProperty("remote_config") + @JsonIgnoreProperties({ + "customParametersProvider", + "blockHandler", + "customLoginResponseValidator", + "credentialsCustomExtractor", + "customIsSensitiveRequest", + "customParametersExtraction", + "filterByCustomFunction", + "loggerFactory", + "telemetryConfig", + "reverseProxyInstance", + "ipxHttpClientInstance", + "ipxhttpClientInstance", + "IPXHttpClientInstance", + "pxClientInstance", + "PXClientInstance", + "pxclientInstance", + "httpClient", + "pxClient", + "pxReverseProxy" + }) + public PXConfiguration remoteConfig; +} diff --git a/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java b/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java index 678e1f80..bcb5aaf6 100644 --- a/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java +++ b/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java @@ -312,16 +312,49 @@ public static void setPxLoggerSeverity(LoggerSeverity severity) { * @return Configuration Object clone without cookieKey and authToken **/ public PXConfiguration getTelemetryConfig() { - int trailingChars = 4; - String redactedPrefix = "***REDACTED***"; - String redactedAuthToken = redactedPrefix.concat(this.authToken.substring(this.authToken.length() - trailingChars)); - List redactedCookieKeys = this.cookieKeys.stream().map((key) -> "***REDACTED***".concat(key.substring(key.length() - trailingChars))).collect(Collectors.toList()); - String redactedLoggerAuthToken = this.loggerAuthToken.isEmpty() ? null : redactedPrefix.concat(this.loggerAuthToken.substring(this.loggerAuthToken.length() - trailingChars)); - return this.toBuilder() - .authToken(redactedAuthToken) - .cookieKeys(redactedCookieKeys) - .loggerAuthToken(redactedLoggerAuthToken) + + PXConfiguration telemetry = this.toBuilder() + .authToken(this.redactString(this.authToken)) + .clearCookieKeys() + .cookieKeys(this.cookieKeys.stream().map(this::redactString).collect(Collectors.toList())) + .loggerAuthToken(this.redactString(this.loggerAuthToken)) + .sensitiveRoutesRegex(this.stringifyRegexSet(this.sensitiveRoutesRegex)) + // prune non-serializable/runtime members for telemetry clone + .customParametersProvider(null) + .blockHandler(null) + .customLoginResponseValidator(null) + .credentialsCustomExtractor(null) + .customIsSensitiveRequest(null) + .customParametersExtraction(null) + .filterByCustomFunction(null) + .loggerFactory(null) + .httpClient(null) + .pxClient(null) + .pxReverseProxy(null) .build(); + // ensure transient instances are not serialized + telemetry.pxClientInstance = null; + telemetry.ipxHttpClientInstance = null; + telemetry.reverseProxyInstance = null; + return telemetry; + } + + private Set stringifyRegexSet(Set regexSet) { + if (regexSet == null) { + return null; + } + return regexSet.stream() + .map(r -> r != null && r.startsWith("_REGEXP ") ? r : "_REGEXP /" + r + "/") + .collect(Collectors.toSet()); + } + + private String redactString(String str) { + int trailingChars = 5; + String redactedPrefix = "***REDACTED***"; + if (str == null || str.length() <= trailingChars) { + return redactedPrefix; + } + return redactedPrefix.concat(str.substring(str.length() - trailingChars)); } public void disableModule() { From 129252128b6a4c1b1ea250976f51fd1547f2f9e5 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 10:36:05 -0700 Subject: [PATCH 16/46] fix: ci_files config and px_metadata excluded tests (custom function hashes in telemetry) --- ci_files/enforcer-config.json | 3 --- px_metadata.json | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ci_files/enforcer-config.json b/ci_files/enforcer-config.json index 6f3ed977..e0bd186c 100644 --- a/ci_files/enforcer-config.json +++ b/ci_files/enforcer-config.json @@ -19,9 +19,6 @@ "px_custom_first_party_xhr_endpoint": "/custom_first_party_xhr_endpoint", "px_custom_first_party_captcha_endpoint": "/custom_first_party_captcha_endpoint", "px_custom_first_party_prefix": "/custom_first_party_prefix", - "px_filter_by_route": [ - "/filtered_route" - ], "px_monitored_routes": [ "/monitored_route", "/monitored_route/suffix", diff --git a/px_metadata.json b/px_metadata.json index 041b8c7c..0e52f582 100644 --- a/px_metadata.json +++ b/px_metadata.json @@ -48,6 +48,7 @@ "test_block_page_captcha_response_contains_http_reason_phrase", "test_cookie_v3_cookie_decryption_failed_iterations_above_max_allowed_value", "test_cookie_v3_cookie_validation_failed_big_cookie", - "test_client_ip_extraction_order_risk_api" + "test_client_ip_extraction_order_risk_api", + "test_telemetry_command_verify_custom_function_hash" ] } From 08c9bb9fa07e4f5bde9876ce8ca3fc2774b3a149 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 10:36:41 -0700 Subject: [PATCH 17/46] feat: allow non-string types in Custom Parameters (backwards-compatible change) --- .../models/risk/CustomParameters.java | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/perimeterx/models/risk/CustomParameters.java b/src/main/java/com/perimeterx/models/risk/CustomParameters.java index 6a51cb9c..34e4c993 100644 --- a/src/main/java/com/perimeterx/models/risk/CustomParameters.java +++ b/src/main/java/com/perimeterx/models/risk/CustomParameters.java @@ -6,30 +6,32 @@ /** * Created by nitzangoldfeder on 03/04/2018. */ + +// Note: Parameters are of type Object to allow flexibility in the type of data being sent (e.g., String, Number, Boolean, etc.) @JsonInclude(JsonInclude.Include.NON_NULL) public class CustomParameters { @JsonProperty("custom_param1") - public String customParam1; + public Object customParam1; @JsonProperty("custom_param2") - public String customParam2; + public Object customParam2; @JsonProperty("custom_param3") - public String customParam3; + public Object customParam3; @JsonProperty("custom_param4") - public String customParam4; + public Object customParam4; @JsonProperty("custom_param5") - public String customParam5; + public Object customParam5; @JsonProperty("custom_param6") - public String customParam6; + public Object customParam6; @JsonProperty("custom_param7") - public String customParam7; + public Object customParam7; @JsonProperty("custom_param8") - public String customParam8; + public Object customParam8; @JsonProperty("custom_param9") - public String customParam9; + public Object customParam9; @JsonProperty("custom_param10") - public String customParam10; + public Object customParam10; - public String getCustomParam1() { + public Object getCustomParam1() { return customParam1; } @@ -37,7 +39,7 @@ public void setCustomParam1(String customParam1) { this.customParam1 = customParam1; } - public String getCustomParam2() { + public Object getCustomParam2() { return customParam2; } @@ -45,7 +47,7 @@ public void setCustomParam2(String customParam2) { this.customParam2 = customParam2; } - public String getCustomParam3() { + public Object getCustomParam3() { return customParam3; } @@ -53,7 +55,7 @@ public void setCustomParam3(String customParam3) { this.customParam3 = customParam3; } - public String getCustomParam4() { + public Object getCustomParam4() { return customParam4; } @@ -61,7 +63,7 @@ public void setCustomParam4(String customParam4) { this.customParam4 = customParam4; } - public String getCustomParam5() { + public Object getCustomParam5() { return customParam5; } @@ -69,7 +71,7 @@ public void setCustomParam5(String customParam5) { this.customParam5 = customParam5; } - public String getCustomParam6() { + public Object getCustomParam6() { return customParam6; } @@ -77,7 +79,7 @@ public void setCustomParam6(String customParam6) { this.customParam6 = customParam6; } - public String getCustomParam7() { + public Object getCustomParam7() { return customParam7; } @@ -85,7 +87,7 @@ public void setCustomParam7(String customParam7) { this.customParam7 = customParam7; } - public String getCustomParam8() { + public Object getCustomParam8() { return customParam8; } @@ -93,7 +95,7 @@ public void setCustomParam8(String customParam8) { this.customParam8 = customParam8; } - public String getCustomParam9() { + public Object getCustomParam9() { return customParam9; } @@ -101,7 +103,7 @@ public void setCustomParam9(String customParam9) { this.customParam9 = customParam9; } - public String getCustomParam10() { + public Object getCustomParam10() { return customParam10; } From 697fcbe7c79384d3bb9b6eadd41dd0bee1a3aadf Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 10:37:15 -0700 Subject: [PATCH 18/46] update: configs in example --- web/src/main/java/com/web/Config.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/web/src/main/java/com/web/Config.java b/web/src/main/java/com/web/Config.java index 0dc57323..5e092baf 100644 --- a/web/src/main/java/com/web/Config.java +++ b/web/src/main/java/com/web/Config.java @@ -175,13 +175,18 @@ public PXConfiguration getPxConfiguration() { CustomParameters customParameters = new CustomParameters(); customParameters.customParam1 = "test1"; customParameters.customParam2 = "test2"; - customParameters.customParam3 = "3"; - customParameters.customParam4 = "4"; - customParameters.customParam5 = "5"; - customParameters.customParam6 = "6"; + customParameters.customParam3 = 3; + customParameters.customParam4 = 4; + customParameters.customParam5 = 5; + customParameters.customParam6 = 6; + customParameters.customParam7 = req.getRequestURI(); return customParameters; }); + builder.customIsSensitiveRequest((req -> { + return req.getRequestURI().startsWith("/sensitive") && req.getMethod().equals("POST"); + })); + return builder.build(); } From 3425343871eec3d6337035ed803a92ac73896c41 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 12:20:47 -0700 Subject: [PATCH 19/46] feat: added px_secured_pxhd_enabled configuration --- ci_files/enforcer-config.json | 3 ++- .../api/verificationhandler/DefaultVerificationHandler.java | 6 ++++-- .../perimeterx/models/configuration/PXConfiguration.java | 4 ++++ web/src/main/java/com/web/Config.java | 3 +++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/ci_files/enforcer-config.json b/ci_files/enforcer-config.json index e0bd186c..b085b4f1 100644 --- a/ci_files/enforcer-config.json +++ b/ci_files/enforcer-config.json @@ -113,5 +113,6 @@ ], "px_cors_support_enabled": true, "px_cors_preflight_request_filter_enabled": true, - "px_url_decode_reserved_characters": true + "px_url_decode_reserved_characters": true, + "px_secured_pxhd_enabled": true } \ No newline at end of file diff --git a/src/main/java/com/perimeterx/api/verificationhandler/DefaultVerificationHandler.java b/src/main/java/com/perimeterx/api/verificationhandler/DefaultVerificationHandler.java index 716dcfee..cdb193f3 100644 --- a/src/main/java/com/perimeterx/api/verificationhandler/DefaultVerificationHandler.java +++ b/src/main/java/com/perimeterx/api/verificationhandler/DefaultVerificationHandler.java @@ -1,13 +1,11 @@ package com.perimeterx.api.verificationhandler; -import com.perimeterx.api.PerimeterX; import com.perimeterx.api.activities.ActivityHandler; import com.perimeterx.api.additionalContext.PXHDSource; import com.perimeterx.api.blockhandler.BlockHandler; import com.perimeterx.models.PXContext; import com.perimeterx.models.configuration.PXConfiguration; import com.perimeterx.models.exceptions.PXException; -import com.perimeterx.utils.logger.IPXLogger; import com.perimeterx.utils.logger.LogReason; import javax.servlet.http.HttpServletResponseWrapper; @@ -96,6 +94,10 @@ private String getPxhdCookie(PXContext context) throws UnsupportedEncodingExcept cookieValue += COOKIE_SEPARATOR + COOKIE_DOMAIN_KEY + context.getPxhdDomain(); } + if (pxConfiguration.isSecuredPxhdEnabled()) { + cookieValue += COOKIE_SEPARATOR + "Secure"; + } + return cookieValue; } diff --git a/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java b/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java index bcb5aaf6..6904f6a1 100644 --- a/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java +++ b/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java @@ -256,6 +256,10 @@ public static void setPxLoggerSeverity(LoggerSeverity severity) { @JsonProperty("px_login_successful_status") private int[] loginResponseValidationStatusCode = {200}; + @Builder.Default + @JsonProperty("px_secured_pxhd_enabled") + private boolean securedPxhdEnabled = false; + @Builder.Default private LoginResponseValidator customLoginResponseValidator = new DefaultCustomLoginResponseValidator(); diff --git a/web/src/main/java/com/web/Config.java b/web/src/main/java/com/web/Config.java index 5e092baf..516860bd 100644 --- a/web/src/main/java/com/web/Config.java +++ b/web/src/main/java/com/web/Config.java @@ -160,6 +160,9 @@ public PXConfiguration getPxConfiguration() { LoggerSeverity.NONE : LoggerSeverity.ERROR; PXConfiguration.setPxLoggerSeverity(loggerSeverity); break; + case "px_secured_pxhd_enabled": + builder.securedPxhdEnabled(enforcerConfig.getBoolean(key)); + break; case "px_user_agent_max_length": case "px_risk_cookie_max_length": case "px_risk_cookie_max_iterations": From 82e5dec8d12d470699df4367ac882fa2c3e19cd9 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 13:17:27 -0700 Subject: [PATCH 20/46] update: tests v1.23.1 --- .github/workflows/ci_e2e.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index d45a3566..e3f0fb10 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -27,7 +27,7 @@ jobs: env: MOCK_COLLECTOR_IMAGE_TAG: 2.0.5 SAMPLE_SITE_IMAGE_TAG: 1.0.0 - ENFORCER_SPEC_TESTS_IMAGE_TAG: 1.21.0 + ENFORCER_SPEC_TESTS_IMAGE_TAG: 1.23.1 runs-on: ubuntu-latest timeout-minutes: 60 From c2b7f6448d6b1eab00c91830dffa53459a398caa Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 13:17:41 -0700 Subject: [PATCH 21/46] fix: exclude ad block test --- px_metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/px_metadata.json b/px_metadata.json index 0e52f582..95597c87 100644 --- a/px_metadata.json +++ b/px_metadata.json @@ -39,6 +39,7 @@ "vid_extraction" ], "excluded_tests": [ + "test_block_activity_ad_block", "test_pxde_extraction_(s2s|unverified|verified)", "test_risk_cookie_valid_cookie_with_user_agent_of_max_length", "test_path_parsing_in_(block|page_requested|risk_api|additional_s2s)\\[with_dots", From 0e83cc39121c3c73b8845b5b98c3dbb63c6349e4 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 13:32:46 -0700 Subject: [PATCH 22/46] update: captcha template --- .../templates/captcha_template.mustache | 127 +++++++++--------- 1 file changed, 64 insertions(+), 63 deletions(-) diff --git a/src/main/resources/com/perimeterx/api/blockhandler/templates/captcha_template.mustache b/src/main/resources/com/perimeterx/api/blockhandler/templates/captcha_template.mustache index 4a1503bf..38407441 100644 --- a/src/main/resources/com/perimeterx/api/blockhandler/templates/captcha_template.mustache +++ b/src/main/resources/com/perimeterx/api/blockhandler/templates/captcha_template.mustache @@ -6,74 +6,75 @@ Access to this page has been denied {{#cssRef}} - + {{/cssRef}} - -{{#jsRef}} - -{{/jsRef}} + function isContentLoaded() { + return !!document.querySelector('div,span'); + } + window._pxOnError = function () { + var style = document.createElement('style'); + style.innerText = '@import url(https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap);body{background-color:#fafbfc}.px-captcha-error-container{position:fixed;height:340px;background-color:#fff;font-family:Roboto,sans-serif}.px-captcha-error-header{color:#f0f1f2;font-size:29px;margin:67px 0 33px;font-weight:500;line-height:.83;text-align:center}.px-captcha-error-message{color:#f0f1f2;font-size:18px;margin:0 0 29px;line-height:1.33;text-align:center}.px-captcha-error-button{text-align:center;line-height:48px;width:253px;margin:auto;border-radius:50px;border:solid 1px #f0f1f2;font-size:20px;color:#f0f1f2}.px-captcha-error-wrapper{margin:18px 0 0}div.px-captcha-error{margin:auto;text-align:center;width:400px;height:30px;font-size:12px;background-color:#fcf0f2;color:#ce0e2d}img.px-captcha-error{margin:6px 8px -2px 0}.px-captcha-error-refid{border-top:solid 1px #f0eeee;height:27px;margin:13px 0 0;border-radius:0 0 3px 3px;background-color:#fafbfc;font-size:10px;line-height:2.5;text-align:center;color:#b1b5b8}@media (min-width:620px){.px-captcha-error-container{width:530px;top:50%;left:50%;margin-top:-170px;margin-left:-265px;border-radius:3px;box-shadow:0 2px 9px -1px rgba(0,0,0,.13)}}@media (min-width:481px) and (max-width:620px){.px-captcha-error-container{width:85%;top:50%;left:50%;margin-top:-170px;margin-left:-42.5%;border-radius:3px;box-shadow:0 2px 9px -1px rgba(0,0,0,.13)}}@media (max-width:480px){body{background-color:#fff}.px-captcha-error-header{color:#f0f1f2;font-size:29px;margin:55px 0 33px}.px-captcha-error-container{width:530px;top:50%;left:50%;margin-top:-170px;margin-left:-265px}.px-captcha-error-refid{position:fixed;width:100%;left:0;bottom:0;border-radius:0;font-size:14px;line-height:2}}@media (max-width:390px){div.px-captcha-error{font-size:10px}.px-captcha-error-refid{font-size:11px;line-height:2.5}}'; + document.head.appendChild(style); + var div = document.createElement('div'); + div.className = 'px-captcha-error-container'; + div.innerHTML = '
Before we continue...
Press & Hold to confirm you are
a human (and not a bot).
Press & Hold
Please check your internet connection' + (window._pxMobile ? '' : ' or disable your ad-blocker') + '.
Reference ID ' + window._pxUuid + '
'; + document.body.appendChild(div); + if (window._pxMobile) { + setTimeout(function() { + location.href = '/px/captcha_close?status=-1'; + }, 5000); + } + }; + + {{#jsRef}} + + {{/jsRef}} - + \ No newline at end of file From 93e363f84d15df095265da5415b04fa43ca10b62 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 17:07:21 -0700 Subject: [PATCH 23/46] feat: added additional token info --- .../com/perimeterx/internals/cookie/AbstractPXCookie.java | 5 +++++ src/main/java/com/perimeterx/internals/cookie/PXCookie.java | 1 + src/main/java/com/perimeterx/models/PXContext.java | 2 ++ .../perimeterx/models/activities/CommonActivityDetails.java | 4 ++++ .../java/com/perimeterx/models/httpmodels/Additional.java | 6 ++++++ 5 files changed, 18 insertions(+) diff --git a/src/main/java/com/perimeterx/internals/cookie/AbstractPXCookie.java b/src/main/java/com/perimeterx/internals/cookie/AbstractPXCookie.java index d4c40bb8..0899761a 100644 --- a/src/main/java/com/perimeterx/internals/cookie/AbstractPXCookie.java +++ b/src/main/java/com/perimeterx/internals/cookie/AbstractPXCookie.java @@ -186,4 +186,9 @@ public String getUUID() { public String getVID() { return decodedCookie.get("v").asText(); } + + @Override + public String additionalTokenInfo() { + return this.decodedCookie.get("add") != null ? this.decodedCookie.get("add").asText() : null; + } } diff --git a/src/main/java/com/perimeterx/internals/cookie/PXCookie.java b/src/main/java/com/perimeterx/internals/cookie/PXCookie.java index 84d36b5f..3b977af9 100644 --- a/src/main/java/com/perimeterx/internals/cookie/PXCookie.java +++ b/src/main/java/com/perimeterx/internals/cookie/PXCookie.java @@ -23,4 +23,5 @@ public interface PXCookie { boolean isSecured() throws PXException; + String additionalTokenInfo(); } diff --git a/src/main/java/com/perimeterx/models/PXContext.java b/src/main/java/com/perimeterx/models/PXContext.java index 9752eac2..56b7ddd4 100644 --- a/src/main/java/com/perimeterx/models/PXContext.java +++ b/src/main/java/com/perimeterx/models/PXContext.java @@ -233,6 +233,7 @@ public class PXContext { private String pxCtsCookie; private long enforcerStartTime; private boolean isSensitiveRequest; + private String additionalTokenInfo; /** * The cookie key used to decrypt the cookie @@ -460,6 +461,7 @@ public void setOriginalTokenCookie(String originalTokenCookie) { public void setRiskCookie(AbstractPXCookie riskCookie) { this.riskCookie = riskCookie.getDecodedCookie().toString(); + this.additionalTokenInfo = riskCookie.additionalTokenInfo(); } public void setBlockAction(String blockAction) { diff --git a/src/main/java/com/perimeterx/models/activities/CommonActivityDetails.java b/src/main/java/com/perimeterx/models/activities/CommonActivityDetails.java index e66da0d2..f268f5de 100644 --- a/src/main/java/com/perimeterx/models/activities/CommonActivityDetails.java +++ b/src/main/java/com/perimeterx/models/activities/CommonActivityDetails.java @@ -50,6 +50,9 @@ public class CommonActivityDetails implements ActivityDetails { @JsonProperty("additional_risk_info") public String additionalRiskInfo; + @JsonProperty("additional_token_info") + public String additionalTokenInfo; + @JsonProperty("user") public String username; @@ -89,5 +92,6 @@ public CommonActivityDetails(PXContext context) { this.enforcerStartTime = additional.enforcerStartTime; this.pxCtsCookie = additional.pxCtsCookie; this.isSensitiveRoute = additional.isSensitiveRoute; + this.additionalTokenInfo = additional.additionalTokenInfo; } } diff --git a/src/main/java/com/perimeterx/models/httpmodels/Additional.java b/src/main/java/com/perimeterx/models/httpmodels/Additional.java index 228d4a6d..46235630 100644 --- a/src/main/java/com/perimeterx/models/httpmodels/Additional.java +++ b/src/main/java/com/perimeterx/models/httpmodels/Additional.java @@ -85,8 +85,10 @@ public class Additional { @JsonProperty("request_id") public UUID requestId; + @JsonProperty("enforcer_start_time") public long enforcerStartTime; + @JsonProperty("risk_start_time") public long riskStartTime; @@ -96,6 +98,9 @@ public class Additional { @JsonProperty("is_sensitive_route") public Boolean isSensitiveRoute; + @JsonProperty("additional_token_info") + public String additionalTokenInfo; + public static Additional fromContext(PXContext ctx) { Additional additional = new Additional(); additional.pxCookie = ctx.getRiskCookie(); @@ -118,6 +123,7 @@ public static Additional fromContext(PXContext ctx) { additional.riskStartTime = new Date().getTime(); additional.pxCtsCookie = ctx.getPxCtsCookie(); additional.isSensitiveRoute = ctx.isSensitiveRequest(); + additional.additionalTokenInfo = ctx.getAdditionalTokenInfo(); setLoginCredentials(ctx, additional); From dc860f5ca4197df3c1ab0672b8daeb844e63c6b4 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 17:07:40 -0700 Subject: [PATCH 24/46] fix: align new block page (blank space) --- .../api/blockhandler/templates/captcha_template.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/com/perimeterx/api/blockhandler/templates/captcha_template.mustache b/src/main/resources/com/perimeterx/api/blockhandler/templates/captcha_template.mustache index 38407441..bd4aade7 100644 --- a/src/main/resources/com/perimeterx/api/blockhandler/templates/captcha_template.mustache +++ b/src/main/resources/com/perimeterx/api/blockhandler/templates/captcha_template.mustache @@ -6,7 +6,7 @@ Access to this page has been denied {{#cssRef}} - + {{/cssRef}} @@ -77,4 +77,4 @@ {{/jsRef}} - \ No newline at end of file + From e1b9272dd2d0115234931cbc48f8f1f9fedeacee Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 17:08:17 -0700 Subject: [PATCH 25/46] fix: align first party block script with expected value in block page --- .../perimeterx/api/blockhandler/templates/TemplateFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/perimeterx/api/blockhandler/templates/TemplateFactory.java b/src/main/java/com/perimeterx/api/blockhandler/templates/TemplateFactory.java index 998aa3cf..e626ee97 100644 --- a/src/main/java/com/perimeterx/api/blockhandler/templates/TemplateFactory.java +++ b/src/main/java/com/perimeterx/api/blockhandler/templates/TemplateFactory.java @@ -61,7 +61,7 @@ public static Map getProps(PXContext pxContext, PXConfiguration String hostUrl = pxContext.getCollectorURL(); if (pxConfig.isFirstPartyEnabled() && !pxContext.isMobileToken()) { String prefix = pxConfig.getAppId().substring(2); - blockScript = SLASH + prefix + Constants.FIRST_PARTY_CAPTCHA_PATH + QUESTION_MARK + captchaSrcParams; + blockScript = SLASH + prefix + Constants.FIRST_PARTY_CAPTCHA_PATH + CAPTCHA_FIRST_PARTY_FILE_PATH + QUESTION_MARK + captchaSrcParams; jsClientSrc = SLASH + prefix + Constants.FIRST_PARTY_VENDOR_PATH; hostUrl = SLASH + prefix + Constants.FIRST_PARTY_XHR_PATH; } From 5825be3074f6a3d0f810351fe8fda9c2c2fa3a8f Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 27 Oct 2025 17:58:49 -0700 Subject: [PATCH 26/46] chore: changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 809ba2ce..aa6eca50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,14 @@ # Change Log +## [x.x.x] - YYYY-MM-DD +- Added `px_secured_pxhd_enabled` configuration option to enable secure flag on `pxhd` cookie +- Added `is_sensitive_route` to risk api and async activities +- Added `additional_token_info` to risk api and async activities +- Updated telemetry activity to new format (`static_config` and `active_config`; `remote_config` is not supported) +- Updated telemetry activity to include `request_id` +- Updated captcha page template to newest version +- Updated dependencies minor and patch versions (major versions unchanged) +- Changed custom parameters to be of type `Object` instead of `String` to allow more flexibility +- Changed first party block script in captcha template to end with expected `/captcha.js` ## [v6.15.1](https://github.com/PerimeterX/perimeterx-java-sdk/compare/6.15.1...HEAD) (2025-09-08) - Added additional updateReason RISK to Telemetry flow From c1c0aff776bfb4a4baa55cc582b7cdba3eb07886 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Tue, 28 Oct 2025 09:04:00 -0700 Subject: [PATCH 27/46] update: e2e tests to 1.23.2 --- .github/workflows/ci_e2e.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index e3f0fb10..7c109065 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -27,7 +27,7 @@ jobs: env: MOCK_COLLECTOR_IMAGE_TAG: 2.0.5 SAMPLE_SITE_IMAGE_TAG: 1.0.0 - ENFORCER_SPEC_TESTS_IMAGE_TAG: 1.23.1 + ENFORCER_SPEC_TESTS_IMAGE_TAG: 1.23.2 runs-on: ubuntu-latest timeout-minutes: 60 From 147ad3f37c97afe2adaeec8fa3cc7a26794c7da3 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Tue, 28 Oct 2025 09:21:14 -0700 Subject: [PATCH 28/46] fix: adding logger auth token to ci tests --- .github/workflows/ci_e2e.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index 7c109065..6d091a80 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -109,7 +109,8 @@ jobs: cat ./ci_files/enforcer-config.json |\ jq '.px_app_id="${{ secrets.PX_APP_ID }}"' |\ jq '.px_cookie_secret="${{ secrets.TEST_COOKIE_SECRET }}"' |\ - jq '.px_auth_token="${{ secrets.PX_AUTH_TOKEN }}"' > /tmp/enforcer-config.json + jq '.px_auth_token="${{ secrets.PX_AUTH_TOKEN }}"' |\ + jq '.px_logger_auth_token="${{ secrets.PX_LOGGER_AUTH_TOKEN }}"' > /tmp/enforcer-config.json - name: log enforcer config run: cat /tmp/enforcer-config.json From c9e4afd579c0c262b254a7481baa3784c97241db Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Tue, 28 Oct 2025 10:17:09 -0700 Subject: [PATCH 29/46] update: adding retry to e2e tests --- ci_files/spec-tests-values.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ci_files/spec-tests-values.yaml b/ci_files/spec-tests-values.yaml index 2b025ef9..ec158e28 100644 --- a/ci_files/spec-tests-values.yaml +++ b/ci_files/spec-tests-values.yaml @@ -1,3 +1,9 @@ +additionalArgs: + - "--retries" + - "3" + - "--retry-delay" + - "10" + internalMockCollectorURL: "http://mock-collector-mock-collector:3001" siteURL: "http://java-enforcer-sample-site:3000" From 71c18e4b75d4b1f3b61a3912781d8f08b1669421 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 29 Oct 2025 08:50:11 -0700 Subject: [PATCH 30/46] update: mock collector 2.0.5 -> 2.0.6 --- .github/workflows/ci_e2e.yaml | 2 +- .github/workflows/fuzzer.yaml | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index 6d091a80..fc374407 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -25,7 +25,7 @@ jobs: CI: name: "E2E tests" env: - MOCK_COLLECTOR_IMAGE_TAG: 2.0.5 + MOCK_COLLECTOR_IMAGE_TAG: 2.0.6 SAMPLE_SITE_IMAGE_TAG: 1.0.0 ENFORCER_SPEC_TESTS_IMAGE_TAG: 1.23.2 diff --git a/.github/workflows/fuzzer.yaml b/.github/workflows/fuzzer.yaml index f66b6788..e7aac8d1 100644 --- a/.github/workflows/fuzzer.yaml +++ b/.github/workflows/fuzzer.yaml @@ -25,7 +25,7 @@ jobs: Fuzzing: name: "Fuzzing Test" env: - MOCK_COLLECTOR_IMAGE_TAG: 2.0.5 + MOCK_COLLECTOR_IMAGE_TAG: 2.0.6 FUZZER_TAG: 1.1.0 SAMPLE_SITE_IMAGE_TAG: 1.0.0 ENFORCER_TAG: ${{ needs.extract_version.outputs.version }} @@ -55,9 +55,9 @@ jobs: docker build . -t localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG && \ docker push localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG - - uses: azure/setup-helm@v3 + - uses: azure/setup-helm@v4 with: - version: '3.14.2' + version: '3.16.1' - name: Clone helm charts repo - mock-collector uses: actions/checkout@v5 @@ -105,7 +105,8 @@ jobs: --set image.repository=localhost:5001/mock-collector \ --set image.tag=$MOCK_COLLECTOR_IMAGE_TAG \ --set authToken=${{ secrets.PX_AUTH_TOKEN }} \ - --set imagePullPolicy=Always --wait + --set imagePullPolicy=Always \ + --wait - name: set secrets in enforcer config run: | From f081f7fb0db7859e47f5636fb65f69788316a4a0 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 29 Oct 2025 10:24:23 -0700 Subject: [PATCH 31/46] chore: upgrade setup-helm and helm version --- .github/workflows/ci_e2e.yaml | 4 ++-- .github/workflows/fuzzer.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index fc374407..f91d8431 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -50,9 +50,9 @@ jobs: docker build . -t localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG && \ docker push localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG - - uses: azure/setup-helm@v3 + - uses: azure/setup-helm@v4 with: - version: '3.14.1' + version: '3.19.0' - name: Clone helm charts repo - mock-collector uses: actions/checkout@v5 diff --git a/.github/workflows/fuzzer.yaml b/.github/workflows/fuzzer.yaml index e7aac8d1..6027489d 100644 --- a/.github/workflows/fuzzer.yaml +++ b/.github/workflows/fuzzer.yaml @@ -57,7 +57,7 @@ jobs: - uses: azure/setup-helm@v4 with: - version: '3.16.1' + version: '3.19.0' - name: Clone helm charts repo - mock-collector uses: actions/checkout@v5 From 1105074f1e726dc007304c148fe7c3438e36df6e Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Wed, 29 Oct 2025 11:53:52 -0700 Subject: [PATCH 32/46] tmp: setup helm workaround --- .github/workflows/ci_e2e.yaml | 13 ++++++++++--- .github/workflows/fuzzer.yaml | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index f91d8431..223391b3 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -50,9 +50,16 @@ jobs: docker build . -t localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG && \ docker push localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG - - uses: azure/setup-helm@v4 - with: - version: '3.19.0' +# - uses: azure/setup-helm@v4 +# with: +# version: '3.19.0' + + - name: Setup helm (temp) + run: | + curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null + echo "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list + sudo apt-get update + sudo apt-get install helm - name: Clone helm charts repo - mock-collector uses: actions/checkout@v5 diff --git a/.github/workflows/fuzzer.yaml b/.github/workflows/fuzzer.yaml index 6027489d..6b0c5206 100644 --- a/.github/workflows/fuzzer.yaml +++ b/.github/workflows/fuzzer.yaml @@ -55,9 +55,16 @@ jobs: docker build . -t localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG && \ docker push localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG - - uses: azure/setup-helm@v4 - with: - version: '3.19.0' +# - uses: azure/setup-helm@v4 +# with: +# version: '3.19.0' + + - name: Setup helm (temp) + run: | + curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null + echo "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list + sudo apt-get update + sudo apt-get install helm - name: Clone helm charts repo - mock-collector uses: actions/checkout@v5 From e3e90293391d55f41775b8bbb729fa519e18b0bc Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 30 Oct 2025 13:04:54 -0700 Subject: [PATCH 33/46] test: reverting setup-helm, filtering for tests, seeing enforcer logs --- .github/workflows/ci_e2e.yaml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index 223391b3..656e50e5 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -50,16 +50,9 @@ jobs: docker build . -t localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG && \ docker push localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG -# - uses: azure/setup-helm@v4 -# with: -# version: '3.19.0' - - - name: Setup helm (temp) - run: | - curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null - echo "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list - sudo apt-get update - sudo apt-get install helm + - uses: azure/setup-helm@v4 + with: + version: '3.19.0' - name: Clone helm charts repo - mock-collector uses: actions/checkout@v5 @@ -150,6 +143,7 @@ jobs: --set appId=${{ secrets.PX_APP_ID }} \ --set-file enforcerMetadataContent=./px_metadata.json \ --set-file enforcerConfigJsonContent=/tmp/enforcer-config.json \ + --set additionalArgs="-k \"(test_vid_extraction_on_first_party_xhr or test_header_based_logger_logs_on_first_party_requests)\"" \ -f ./ci_files/spec-tests-values.yaml \ --wait \ --timeout 60m0s \ @@ -158,3 +152,7 @@ jobs: - name: get tests results if: ${{ always() }} run: kubectl logs job/enforcer-spec-tests + + - name: get enforcer logs + if: ${{ always() }} + run: kubectl logs deployment/java-enforcer-sample-site From 858677afa3fd0ba8dea8166aaa4fa4adcd4b6895 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 30 Oct 2025 13:10:19 -0700 Subject: [PATCH 34/46] fix --- .github/workflows/ci_e2e.yaml | 1 - ci_files/spec-tests-values.yaml | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index 656e50e5..538cf8e3 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -143,7 +143,6 @@ jobs: --set appId=${{ secrets.PX_APP_ID }} \ --set-file enforcerMetadataContent=./px_metadata.json \ --set-file enforcerConfigJsonContent=/tmp/enforcer-config.json \ - --set additionalArgs="-k \"(test_vid_extraction_on_first_party_xhr or test_header_based_logger_logs_on_first_party_requests)\"" \ -f ./ci_files/spec-tests-values.yaml \ --wait \ --timeout 60m0s \ diff --git a/ci_files/spec-tests-values.yaml b/ci_files/spec-tests-values.yaml index ec158e28..2acd6a57 100644 --- a/ci_files/spec-tests-values.yaml +++ b/ci_files/spec-tests-values.yaml @@ -3,6 +3,8 @@ additionalArgs: - "3" - "--retry-delay" - "10" + - "-k" + - "(test_vid_extraction_on_first_party_xhr or test_header_based_logger_logs_on_first_party_requests)" internalMockCollectorURL: "http://mock-collector-mock-collector:3001" siteURL: "http://java-enforcer-sample-site:3000" From 16d5304baeb3b1b12ae7c788bd53d36ce3ec6861 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 30 Oct 2025 13:27:15 -0700 Subject: [PATCH 35/46] fix: first party log to lowercase --- src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java b/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java index 3158ca86..3360d4df 100644 --- a/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java +++ b/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java @@ -107,7 +107,7 @@ public boolean reversePxXhr(HttpServletRequest req, HttpServletResponse res, PXC final String host = pxConfiguration.getCollectorUrl().replaceFirst("https?:\\/\\/", ""); if (!isValidThirdPartyUrl(url, host, path)) { - context.logger.error("First party XHR URL is inaccurate: " + url + ", rendering default response"); + context.logger.error("first party XHR URL is inaccurate: " + url + ", rendering default response"); predefinedResponseHelper.handlePredefinedResponse(res, predefinedResponse, context); return true; } From ba6999e8e02436c82ff0575dd99fdc9e03857d7b Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 30 Oct 2025 15:02:04 -0700 Subject: [PATCH 36/46] fix: validate third party url with port in host if needed --- ci_files/spec-tests-values.yaml | 2 -- .../api/proxy/DefaultReverseProxy.java | 20 +++++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ci_files/spec-tests-values.yaml b/ci_files/spec-tests-values.yaml index 2acd6a57..ec158e28 100644 --- a/ci_files/spec-tests-values.yaml +++ b/ci_files/spec-tests-values.yaml @@ -3,8 +3,6 @@ additionalArgs: - "3" - "--retry-delay" - "10" - - "-k" - - "(test_vid_extraction_on_first_party_xhr or test_header_based_logger_logs_on_first_party_requests)" internalMockCollectorURL: "http://mock-collector-mock-collector:3001" siteURL: "http://java-enforcer-sample-site:3000" diff --git a/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java b/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java index 3360d4df..4329ed70 100644 --- a/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java +++ b/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java @@ -106,7 +106,7 @@ public boolean reversePxXhr(HttpServletRequest req, HttpServletResponse res, PXC final String url = pxConfiguration.getCollectorUrl() + path; final String host = pxConfiguration.getCollectorUrl().replaceFirst("https?:\\/\\/", ""); - if (!isValidThirdPartyUrl(url, host, path)) { + if (!isValidThirdPartyUrl(url, host, path, context)) { context.logger.error("first party XHR URL is inaccurate: " + url + ", rendering default response"); predefinedResponseHelper.handlePredefinedResponse(res, predefinedResponse, context); return true; @@ -134,13 +134,25 @@ private String getPath(HttpServletRequest req) { return isBlank(req.getRequestURI()) ? "" : req.getRequestURI().substring(xhrPrefix.length()); } - private boolean isValidThirdPartyUrl(String rawThirdPartyUrl, String expectedHost, String expectedUrl) { + private boolean isValidThirdPartyUrl(String rawThirdPartyUrl, String expectedHost, String expectedUrl, PXContext context) { try { URL url = new URL(rawThirdPartyUrl); String uri = url.getPath() + (url.getQuery() != null ? url.getQuery() : ""); - return url.getHost().equalsIgnoreCase(expectedHost) && uri.startsWith(expectedUrl); + if (!uri.startsWith(expectedUrl)) { + context.logger.debug("Validating third party URL failed, expected URL does not match the request URL. expectedUrl: " + expectedUrl + ", requestUrl: " + uri); + return false; + } + String host = url.getHost(); + if (url.getPort() != url.getDefaultPort()) { + host += ":" + url.getPort(); + } + if (!host.equalsIgnoreCase(expectedHost)) { + context.logger.debug("Validating third party URL failed, expected host does not match the request host. expectedHost: " + expectedHost + ", requestHost: " + host); + return false; + } + return true; } catch (Exception e) { - PerimeterX.globalLogger.error("Failed to parse rawUrl. ", e.getMessage()); + context.logger.error("Failed to parse rawUrl. ", e.getMessage()); } return false; From 5b411eb13831b2f134400eb41fd9c3d5f7282a7f Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 30 Oct 2025 15:15:48 -0700 Subject: [PATCH 37/46] fix --- .../java/com/perimeterx/api/proxy/DefaultReverseProxy.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java b/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java index 4329ed70..04ee6728 100644 --- a/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java +++ b/src/main/java/com/perimeterx/api/proxy/DefaultReverseProxy.java @@ -143,8 +143,9 @@ private boolean isValidThirdPartyUrl(String rawThirdPartyUrl, String expectedHos return false; } String host = url.getHost(); - if (url.getPort() != url.getDefaultPort()) { - host += ":" + url.getPort(); + final int port = url.getPort(); + if (port != -1 && port != url.getDefaultPort()) { + host += ":" + port; } if (!host.equalsIgnoreCase(expectedHost)) { context.logger.debug("Validating third party URL failed, expected host does not match the request host. expectedHost: " + expectedHost + ", requestHost: " + host); From d99b16a711c9977abccbe8ee876c08f8117241b5 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 30 Oct 2025 15:36:32 -0700 Subject: [PATCH 38/46] fix: skipping first party timeout test (no fp timeout config supported) --- px_metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/px_metadata.json b/px_metadata.json index 95597c87..fc12507f 100644 --- a/px_metadata.json +++ b/px_metadata.json @@ -50,6 +50,7 @@ "test_cookie_v3_cookie_decryption_failed_iterations_above_max_allowed_value", "test_cookie_v3_cookie_validation_failed_big_cookie", "test_client_ip_extraction_order_risk_api", - "test_telemetry_command_verify_custom_function_hash" + "test_telemetry_command_verify_custom_function_hash", + "test_first_party_timeout" ] } From 1d5ab019625d128d85e98727d7ab7212c7502bfd Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Thu, 30 Oct 2025 16:44:21 -0700 Subject: [PATCH 39/46] try timeout 90 mins --- .github/workflows/fuzzer.yaml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/.github/workflows/fuzzer.yaml b/.github/workflows/fuzzer.yaml index 6b0c5206..526bdfbf 100644 --- a/.github/workflows/fuzzer.yaml +++ b/.github/workflows/fuzzer.yaml @@ -35,7 +35,7 @@ jobs: mode: [ "url", "first_party", "headers", "cookies", "user_agent" ] runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 90 needs: - extract_version @@ -55,16 +55,9 @@ jobs: docker build . -t localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG && \ docker push localhost:5001/java-enforcer-sample-site:$SAMPLE_SITE_IMAGE_TAG -# - uses: azure/setup-helm@v4 -# with: -# version: '3.19.0' - - - name: Setup helm (temp) - run: | - curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null - echo "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list - sudo apt-get update - sudo apt-get install helm + - uses: azure/setup-helm@v4 + with: + version: '3.19.0' - name: Clone helm charts repo - mock-collector uses: actions/checkout@v5 @@ -120,7 +113,8 @@ jobs: cat ./ci_files/enforcer-config.json |\ jq '.px_app_id="${{ secrets.PX_APP_ID }}"' |\ jq '.px_cookie_secret="${{ secrets.TEST_COOKIE_SECRET }}"' |\ - jq '.px_auth_token="${{ secrets.PX_AUTH_TOKEN }}"' > /tmp/enforcer-config.json + jq '.px_auth_token="${{ secrets.PX_AUTH_TOKEN }}"' |\ + jq '.px_logger_auth_token="${{ secrets.PX_LOGGER_AUTH_TOKEN }}"' > /tmp/enforcer-config.json - name: log enforcer config run: cat /tmp/enforcer-config.json @@ -152,7 +146,7 @@ jobs: --set mode=$FUZZ_MODE \ --set siteURL=$SITE_URL \ --wait \ - --timeout 60m0s \ + --timeout 90m0s \ --wait-for-jobs env: FUZZ_MODE: ${{ matrix.mode }} From b0583b2800ba2901d56ed1cb11a14cc3dd55dc7b Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 3 Nov 2025 09:05:23 -0800 Subject: [PATCH 40/46] fix: connection leak bug in first party --- .../java/com/perimeterx/api/proxy/RemoteServer.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/perimeterx/api/proxy/RemoteServer.java b/src/main/java/com/perimeterx/api/proxy/RemoteServer.java index dafc32d2..e69ddb03 100644 --- a/src/main/java/com/perimeterx/api/proxy/RemoteServer.java +++ b/src/main/java/com/perimeterx/api/proxy/RemoteServer.java @@ -109,7 +109,7 @@ public IPXOutgoingRequest prepareProxyRequest() throws IOException { return requestBuilder.build(); } - public IPXIncomingResponse handleResponse(IPXOutgoingRequest proxyRequest, PXContext context) { + public void handleResponse(IPXOutgoingRequest proxyRequest, PXContext context) { IPXIncomingResponse proxyResponse = null; try { // Execute the request @@ -119,7 +119,7 @@ public IPXIncomingResponse handleResponse(IPXOutgoingRequest proxyRequest, PXCon // In failure we can check if we enable predefined request or proxy the original response if (this.isAllowedPredefinedResponse() && statusCode >= HttpStatus.SC_BAD_REQUEST) { predefinedResponseHelper.handlePredefinedResponse(res, predefinedResponse, context); - return proxyResponse; + return; } res.setStatus(statusCode); @@ -143,8 +143,15 @@ public IPXIncomingResponse handleResponse(IPXOutgoingRequest proxyRequest, PXCon if (this.isAllowedPredefinedResponse()) { predefinedResponseHelper.handlePredefinedResponse(res, predefinedResponse, context); } + } finally { + if (proxyResponse != null) { + try { + proxyResponse.close(); + } catch (IOException e) { + context.logger.debug("Failed to close proxy response", e); + } + } } - return proxyResponse; } /** From cf250400144a40b137e2df473707aeb6b528a61f Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 3 Nov 2025 09:29:44 -0800 Subject: [PATCH 41/46] fix: possible telemetry connection leak --- .../com/perimeterx/http/PXHttpClient.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/perimeterx/http/PXHttpClient.java b/src/main/java/com/perimeterx/http/PXHttpClient.java index 93993591..6680fc11 100644 --- a/src/main/java/com/perimeterx/http/PXHttpClient.java +++ b/src/main/java/com/perimeterx/http/PXHttpClient.java @@ -217,14 +217,27 @@ public PXDynamicConfiguration getConfigurationFromServer() { @Override public void sendEnforcerTelemetry(EnforcerTelemetry enforcerTelemetry, PXContext context) throws IOException { - String requestBody = JsonUtils.writer.writeValueAsString(enforcerTelemetry); - if (context!=null){ - context.logger.debug("Sending enforcer telemetry: {}", requestBody); - } else{ - logger.debug("Sending enforcer telemetry: {}", requestBody); + IPXIncomingResponse httpResponse = null; + try { + String requestBody = JsonUtils.writer.writeValueAsString(enforcerTelemetry); + if (context != null) { + context.logger.debug("Sending enforcer telemetry: {}", requestBody); + } else { + logger.debug("Sending enforcer telemetry: {}", requestBody); + } + IPXOutgoingRequest request = buildOutgoingRequest(this.pxConfiguration.getServerURL() + Constants.API_ENFORCER_TELEMETRY, PXHttpMethod.POST, requestBody); + httpResponse = client.send(request); + } catch (Exception e) { + if (context != null) { + context.logger.debug("Sending enforcer telemetry failed. Error: {}", e.getMessage()); + } else { + logger.debug("Sending enforcer telemetry failed. Error: {}", e.getMessage()); + } + } finally { + if (httpResponse != null) { + httpResponse.close(); + } } - IPXOutgoingRequest request = buildOutgoingRequest(this.pxConfiguration.getServerURL() + Constants.API_ENFORCER_TELEMETRY,PXHttpMethod.POST, requestBody); - client.send(request); } private IPXOutgoingRequest buildOutgoingRequest(String url , PXHttpMethod method, String requestBody, BasicHeader... headers) { From 01f3e77cbea8408a486f7b23c52a29a6738d50dd Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 3 Nov 2025 10:57:02 -0800 Subject: [PATCH 42/46] fix: first party max url length enforced, returns 400 --- .../perimeterx/api/proxy/RemoteServer.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/com/perimeterx/api/proxy/RemoteServer.java b/src/main/java/com/perimeterx/api/proxy/RemoteServer.java index e69ddb03..44f810fb 100644 --- a/src/main/java/com/perimeterx/api/proxy/RemoteServer.java +++ b/src/main/java/com/perimeterx/api/proxy/RemoteServer.java @@ -112,6 +112,9 @@ public IPXOutgoingRequest prepareProxyRequest() throws IOException { public void handleResponse(IPXOutgoingRequest proxyRequest, PXContext context) { IPXIncomingResponse proxyResponse = null; try { + if (proxyRequest != null && proxyRequest.getUrl().length() > maxUrlLength) { + throw new IllegalArgumentException("URL too long: " + proxyRequest.getUrl().length()); + } // Execute the request proxyResponse = doExecute(proxyRequest); int statusCode = proxyResponse.status().getStatusCode(); @@ -139,6 +142,9 @@ public void handleResponse(IPXOutgoingRequest proxyRequest, PXContext context) { copyResponseEntity(proxyResponse); } + } catch (IllegalArgumentException e) { + context.logger.debug("Invalid request in first-party proxy: {}", e.getMessage()); + handleClientError(context); } catch (Exception e) { if (this.isAllowedPredefinedResponse()) { predefinedResponseHelper.handlePredefinedResponse(res, predefinedResponse, context); @@ -154,6 +160,19 @@ public void handleResponse(IPXOutgoingRequest proxyRequest, PXContext context) { } } + private void handleClientError(PXContext context) { + try { + res.setStatus(HttpStatus.SC_BAD_REQUEST); + res.setContentType("text/plain"); + res.setCharacterEncoding("UTF-8"); + res.getWriter().print("Bad Request"); + res.getWriter().flush(); + } catch (IOException e) { + context.logger.error("Failed to write error response: {}", e.getMessage()); + res.setStatus(HttpStatus.SC_BAD_REQUEST); + } + } + /** * Copy response body data (the entity) from the proxy to the servlet client. */ From 06b526888941ca78c42e1a860cce9b0012da9fa4 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 3 Nov 2025 12:38:58 -0800 Subject: [PATCH 43/46] refactor: set logger severity in example --- web/src/main/java/com/web/Config.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/web/src/main/java/com/web/Config.java b/web/src/main/java/com/web/Config.java index 516860bd..462b3a05 100644 --- a/web/src/main/java/com/web/Config.java +++ b/web/src/main/java/com/web/Config.java @@ -155,10 +155,7 @@ public PXConfiguration getPxConfiguration() { builder.loginResponseValidationStatusCode(extractStatusCode(key)); break; case "px_logger_severity": - LoggerSeverity loggerSeverity = LoggerSeverity.DEBUG.jsonName().equals(enforcerConfig.getString(key)) ? - LoggerSeverity.DEBUG : LoggerSeverity.NONE.jsonName().equals(enforcerConfig.getString(key)) ? - LoggerSeverity.NONE : LoggerSeverity.ERROR; - PXConfiguration.setPxLoggerSeverity(loggerSeverity); + this.setLoggerSeverity(enforcerConfig.getString(key)); break; case "px_secured_pxhd_enabled": builder.securedPxhdEnabled(enforcerConfig.getBoolean(key)); @@ -193,6 +190,20 @@ public PXConfiguration getPxConfiguration() { return builder.build(); } + private void setLoggerSeverity(String severity) { + switch (severity) { + case "debug": + PXConfiguration.setPxLoggerSeverity(LoggerSeverity.DEBUG); + break; + case "error": + PXConfiguration.setPxLoggerSeverity(LoggerSeverity.ERROR); + break; + case "none": + PXConfiguration.setPxLoggerSeverity(LoggerSeverity.NONE); + break; + } + } + private int[] extractStatusCode(String key) { final JSONArray jsonField = enforcerConfig.getJSONArray(key); final int[] statusCode = new int[jsonField.length()]; From 991e2ada75e3f7b5628a65f4df7ab21d3e10b3cc Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Mon, 3 Nov 2025 12:40:06 -0800 Subject: [PATCH 44/46] chore: changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa6eca50..db763821 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ - Updated dependencies minor and patch versions (major versions unchanged) - Changed custom parameters to be of type `Object` instead of `String` to allow more flexibility - Changed first party block script in captcha template to end with expected `/captcha.js` +- Fixed possible connection leak issue due to unclosed responses in first party and telemetry requests +- Fixed first party fuzzing errors by returning 400 on first party requests with URL length > 1000 characters ## [v6.15.1](https://github.com/PerimeterX/perimeterx-java-sdk/compare/6.15.1...HEAD) (2025-09-08) - Added additional updateReason RISK to Telemetry flow From df32e9fc89c46916831851b5d5503893cbe0ab1b Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Tue, 4 Nov 2025 07:24:06 -0800 Subject: [PATCH 45/46] pr fixes: test v1.23.3 --- .github/workflows/ci.yml | 2 +- .github/workflows/ci_e2e.yaml | 2 +- .github/workflows/fuzzer.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b29753ae..c541b8b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Set up JDK 8 uses: actions/setup-java@v3 with: diff --git a/.github/workflows/ci_e2e.yaml b/.github/workflows/ci_e2e.yaml index 538cf8e3..3a8e52e6 100644 --- a/.github/workflows/ci_e2e.yaml +++ b/.github/workflows/ci_e2e.yaml @@ -27,7 +27,7 @@ jobs: env: MOCK_COLLECTOR_IMAGE_TAG: 2.0.6 SAMPLE_SITE_IMAGE_TAG: 1.0.0 - ENFORCER_SPEC_TESTS_IMAGE_TAG: 1.23.2 + ENFORCER_SPEC_TESTS_IMAGE_TAG: 1.23.3 runs-on: ubuntu-latest timeout-minutes: 60 diff --git a/.github/workflows/fuzzer.yaml b/.github/workflows/fuzzer.yaml index 526bdfbf..c703e737 100644 --- a/.github/workflows/fuzzer.yaml +++ b/.github/workflows/fuzzer.yaml @@ -35,7 +35,7 @@ jobs: mode: [ "url", "first_party", "headers", "cookies", "user_agent" ] runs-on: ubuntu-latest - timeout-minutes: 90 + timeout-minutes: 60 needs: - extract_version @@ -146,7 +146,7 @@ jobs: --set mode=$FUZZ_MODE \ --set siteURL=$SITE_URL \ --wait \ - --timeout 90m0s \ + --timeout 60m0s \ --wait-for-jobs env: FUZZ_MODE: ${{ matrix.mode }} From 52a0445d66773c988f0676971668313de513eb66 Mon Sep 17 00:00:00 2001 From: Ori Gold Date: Tue, 4 Nov 2025 13:18:05 -0800 Subject: [PATCH 46/46] pr fix: json ignore properties moved to pxconfiguration --- .../EnforcerTelemetryActivityDetails.java | 71 ++----------------- .../models/configuration/PXConfiguration.java | 22 ++++++ 2 files changed, 29 insertions(+), 64 deletions(-) diff --git a/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java b/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java index c2f5a576..fdda722e 100644 --- a/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java +++ b/src/main/java/com/perimeterx/models/activities/EnforcerTelemetryActivityDetails.java @@ -1,7 +1,6 @@ package com.perimeterx.models.activities; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.google.gson.JsonIOException; import com.perimeterx.models.PXContext; import com.perimeterx.models.configuration.PXConfiguration; @@ -18,14 +17,19 @@ public class EnforcerTelemetryActivityDetails implements ActivityDetails { @JsonProperty("module_version") private String moduleVersion; + @JsonProperty("enforcer_configs") private TelemetryConfiguration enforcerConfigs; + @JsonProperty("os_name") private String osName; + @JsonProperty("node_name") private String nodeName; + @JsonProperty("update_reason") private UpdateReason updateReason; + @JsonProperty("request_id") private UUID requestId; @@ -74,72 +78,11 @@ public UUID getRequestId() { class TelemetryConfiguration { @JsonProperty("active_config") - @JsonIgnoreProperties({ - "customParametersProvider", - "blockHandler", - "customLoginResponseValidator", - "credentialsCustomExtractor", - "customIsSensitiveRequest", - "customParametersExtraction", - "filterByCustomFunction", - "loggerFactory", - "telemetryConfig", - "reverseProxyInstance", - "ipxHttpClientInstance", - "ipxhttpClientInstance", - "IPXHttpClientInstance", - "pxClientInstance", - "PXClientInstance", - "pxclientInstance", - "httpClient", - "pxClient", - "pxReverseProxy" - }) public PXConfiguration activeConfig; + @JsonProperty("static_config") - @JsonIgnoreProperties({ - "customParametersProvider", - "blockHandler", - "customLoginResponseValidator", - "credentialsCustomExtractor", - "customIsSensitiveRequest", - "customParametersExtraction", - "filterByCustomFunction", - "loggerFactory", - "telemetryConfig", - "reverseProxyInstance", - "ipxHttpClientInstance", - "ipxhttpClientInstance", - "IPXHttpClientInstance", - "pxClientInstance", - "PXClientInstance", - "pxclientInstance", - "httpClient", - "pxClient", - "pxReverseProxy" - }) public PXConfiguration staticConfig; + @JsonProperty("remote_config") - @JsonIgnoreProperties({ - "customParametersProvider", - "blockHandler", - "customLoginResponseValidator", - "credentialsCustomExtractor", - "customIsSensitiveRequest", - "customParametersExtraction", - "filterByCustomFunction", - "loggerFactory", - "telemetryConfig", - "reverseProxyInstance", - "ipxHttpClientInstance", - "ipxhttpClientInstance", - "IPXHttpClientInstance", - "pxClientInstance", - "PXClientInstance", - "pxclientInstance", - "httpClient", - "pxClient", - "pxReverseProxy" - }) public PXConfiguration remoteConfig; } diff --git a/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java b/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java index 6904f6a1..8bb1baad 100644 --- a/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java +++ b/src/main/java/com/perimeterx/models/configuration/PXConfiguration.java @@ -1,6 +1,7 @@ package com.perimeterx.models.configuration; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.perimeterx.api.PerimeterX; import com.perimeterx.api.additionalContext.credentialsIntelligence.CIProtocol; @@ -48,6 +49,27 @@ @AllArgsConstructor @NoArgsConstructor @Getter +@JsonIgnoreProperties({ + "customParametersProvider", + "blockHandler", + "customLoginResponseValidator", + "credentialsCustomExtractor", + "customIsSensitiveRequest", + "customParametersExtraction", + "filterByCustomFunction", + "loggerFactory", + "telemetryConfig", + "reverseProxyInstance", + "ipxHttpClientInstance", + "ipxhttpClientInstance", + "IPXHttpClientInstance", + "pxClientInstance", + "PXClientInstance", + "pxclientInstance", + "httpClient", + "pxClient", + "pxReverseProxy" +}) public class PXConfiguration { private static LoggerSeverity loggerSeverity = null;