From ea276a8cb4293bb5adbc89720c3364f605eef4cd Mon Sep 17 00:00:00 2001 From: Velimir Majstorov Date: Mon, 17 Aug 2026 12:30:35 +0200 Subject: [PATCH 1/4] chore(deps): bump toolchain and run gitleaks CLI without license - Kotlin 2.3.21 -> 2.4.20-RC (fixes CVE-2026-53914 unsafe deserialization in build cache; only pre-release toolchain carries the patch) - KSP 2.3.10 -> 2.3.11, compose-bom 2026.06.01 -> 2026.08.00, appcompat 1.7.1 -> 1.8.0, gradle wrapper 9.6.1 -> 9.7.0 - Replace gitleaks/gitleaks-action@v2 (requires paid org license) with the pinned MIT gitleaks CLI so the secrets scan passes on org-owned repos --- .github/workflows/security-secrets-scan.yml | 11 ++++++++--- gradle/libs.versions.toml | 8 ++++---- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/security-secrets-scan.yml b/.github/workflows/security-secrets-scan.yml index 9b2da08..bdff43b 100644 --- a/.github/workflows/security-secrets-scan.yml +++ b/.github/workflows/security-secrets-scan.yml @@ -32,8 +32,13 @@ jobs: with: fetch-depth: 0 + # The gitleaks GitHub Action (gitleaks/gitleaks-action@v2) requires a paid + # license for organization-owned repos. The gitleaks CLI itself is MIT and + # free, so we run the pinned binary directly to scan full git history. - name: Run Gitleaks - uses: gitleaks/gitleaks-action@v2 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} + GITLEAKS_VERSION: 8.30.1 + run: | + curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ + | tar -xz gitleaks + ./gitleaks git . --redact --verbose --exit-code 1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5e2bdab..bb9ecc6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,17 +8,17 @@ coroutinesTest = "1.11.0" testCore = "1.7.0" lifecycleRuntimeKtx = "2.11.0" activityCompose = "1.13.0" -kotlin = "2.3.21" -composeBom = "2026.06.01" +kotlin = "2.4.20-RC" +composeBom = "2026.08.00" room = "2.8.4" sqlite = "2.7.0" sqlcipher = "4.17.0" argon2kt = "1.6.0" tink = "1.23.0" work = "2.11.2" -ksp = "2.3.10" +ksp = "2.3.11" biometric = "1.1.0" -appcompat = "1.7.1" +appcompat = "1.8.0" playServicesAds = "25.4.0" playServicesCodeScanner = "16.1.0" playIntegrity = "1.6.0" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index dbe66e1..84c5a9c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14 -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip +distributionSha256Sum=84fbba45c7f4c64abc77460e1c00f541e9f960e3c7ed2538f1ede19eacd873ae +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 From 7d512df66b61ae595eb9092ea18498ce45cfe5d9 Mon Sep 17 00:00:00 2001 From: Velimir Majstorov Date: Mon, 17 Aug 2026 12:33:04 +0200 Subject: [PATCH 2/4] ci: allowlist non-secret format-label constant in gitleaks scan The gitleaks CLI (unlike the previously-broken licensed action) actually runs and flagged FORMAT_XCHACHA_KEY = "xchacha20poly1305_key" as a generic-api-key false positive. Add a .gitleaks.toml allowlist for that algorithm identifier and pass it explicitly to the scan. --- .github/workflows/security-secrets-scan.yml | 2 +- .gitleaks.toml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 .gitleaks.toml diff --git a/.github/workflows/security-secrets-scan.yml b/.github/workflows/security-secrets-scan.yml index bdff43b..f85e998 100644 --- a/.github/workflows/security-secrets-scan.yml +++ b/.github/workflows/security-secrets-scan.yml @@ -41,4 +41,4 @@ jobs: run: | curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ | tar -xz gitleaks - ./gitleaks git . --redact --verbose --exit-code 1 + ./gitleaks git . --config .gitleaks.toml --redact --verbose --exit-code 1 diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..fb5dbd0 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,16 @@ +# Gitleaks configuration for NULVEX — extends the built-in ruleset. +title = "NULVEX gitleaks config" + +[extend] +useDefault = true + +[[allowlists]] +description = """ +Non-secret format-label constants. These are algorithm identifiers stored as +JSON "format" field values (not credentials); the generic-api-key rule trips on +the variable name containing KEY plus the string entropy. +""" +regexTarget = "match" +regexes = [ + '''xchacha20poly1305_key''', +] From 271a375d3dd76b1c4aee2fbcde5a26b8e082ef8b Mon Sep 17 00:00:00 2001 From: Velimir Majstorov Date: Mon, 17 Aug 2026 12:40:15 +0200 Subject: [PATCH 3/4] ci: switch CodeQL to build-mode none for Kotlin 2.4.20-RC CodeQL's build-tracer extractor rejects Kotlin 2.4.20-RC (KotlinVersionTooRecentError: supports versions below 2.4.20). Buildless source extraction avoids compiling under the tracer, so analysis no longer depends on the extractor keeping pace with the compiler version. --- .github/workflows/security-codeql.yml | 52 +++------------------------ 1 file changed, 4 insertions(+), 48 deletions(-) diff --git a/.github/workflows/security-codeql.yml b/.github/workflows/security-codeql.yml index 642a80a..9aeb3a3 100644 --- a/.github/workflows/security-codeql.yml +++ b/.github/workflows/security-codeql.yml @@ -37,58 +37,14 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: "17" - cache: gradle - - - name: Prepare google-services.json - env: - GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} - run: | - if [ -n "$GOOGLE_SERVICES_JSON" ]; then - printf '%s' "$GOOGLE_SERVICES_JSON" > app/google-services.json - else - cat > app/google-services.json <<'JSON' - { - "project_info": { - "project_number": "0", - "project_id": "nulvex-ci", - "storage_bucket": "nulvex-ci.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:0:android:0000000000000000", - "android_client_info": { - "package_name": "com.androidircx.nulvex" - } - }, - "api_key": [ - { - "current_key": "dummy" - } - ] - } - ], - "configuration_version": "1" - } - JSON - fi - + # Buildless source extraction. CodeQL's build-tracer extractor rejects + # Kotlin versions it doesn't yet support (e.g. 2.4.20-RC), so we avoid + # compiling under the tracer and analyze the sources directly. - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - build-mode: manual - - - name: Make Gradle executable - run: chmod +x ./gradlew - - - name: Build for analysis - run: ./gradlew :app:assembleDebug --no-daemon --stacktrace + build-mode: none - name: Perform CodeQL analysis uses: github/codeql-action/analyze@v4 From f2ad3a2bc6048fcf93d9d1ca6c139a5e77f4b9df Mon Sep 17 00:00:00 2001 From: Velimir Majstorov Date: Mon, 17 Aug 2026 12:48:38 +0200 Subject: [PATCH 4/4] =?UTF-8?q?revert:=20keep=20Kotlin=202.3.21=20?= =?UTF-8?q?=E2=80=94=20CodeQL=20cannot=20analyze=202.4.20=20yet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CVE-2026-53914's only patched Kotlin (>= 2.4.20-Beta1) is rejected by CodeQL's extractor (supports < 2.4.20), and buildless mode extracts no Kotlin sources either. The two requirements are mutually exclusive right now, so roll Kotlin back to 2.3.21 and restore the build-based CodeQL analysis. The build-cache deserialization alert is tracked separately and does not affect the shipped artifact. Revisit when a stable Kotlin 2.4.20 lands with CodeQL support. Retains: gradle 9.7.0, compose-bom 2026.08.00, appcompat 1.8.0, KSP 2.3.11, and the license-free gitleaks scan. --- .github/workflows/security-codeql.yml | 52 ++++++++++++++++++++++++--- gradle/libs.versions.toml | 2 +- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/.github/workflows/security-codeql.yml b/.github/workflows/security-codeql.yml index 9aeb3a3..642a80a 100644 --- a/.github/workflows/security-codeql.yml +++ b/.github/workflows/security-codeql.yml @@ -37,14 +37,58 @@ jobs: - name: Checkout uses: actions/checkout@v4 - # Buildless source extraction. CodeQL's build-tracer extractor rejects - # Kotlin versions it doesn't yet support (e.g. 2.4.20-RC), so we avoid - # compiling under the tracer and analyze the sources directly. + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "17" + cache: gradle + + - name: Prepare google-services.json + env: + GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} + run: | + if [ -n "$GOOGLE_SERVICES_JSON" ]; then + printf '%s' "$GOOGLE_SERVICES_JSON" > app/google-services.json + else + cat > app/google-services.json <<'JSON' + { + "project_info": { + "project_number": "0", + "project_id": "nulvex-ci", + "storage_bucket": "nulvex-ci.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:0:android:0000000000000000", + "android_client_info": { + "package_name": "com.androidircx.nulvex" + } + }, + "api_key": [ + { + "current_key": "dummy" + } + ] + } + ], + "configuration_version": "1" + } + JSON + fi + - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - build-mode: none + build-mode: manual + + - name: Make Gradle executable + run: chmod +x ./gradlew + + - name: Build for analysis + run: ./gradlew :app:assembleDebug --no-daemon --stacktrace - name: Perform CodeQL analysis uses: github/codeql-action/analyze@v4 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bb9ecc6..19390b1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ coroutinesTest = "1.11.0" testCore = "1.7.0" lifecycleRuntimeKtx = "2.11.0" activityCompose = "1.13.0" -kotlin = "2.4.20-RC" +kotlin = "2.3.21" composeBom = "2026.08.00" room = "2.8.4" sqlite = "2.7.0"