← Writing

GitLab2Shell Response: CVE-2026-110264 Version Checks and Upgrade Paths

On this page

GitLab2Shell remediation means upgrading GitLab CE/EE to a release fixing CVE-2026-110264 and verifying deployment adoption. GitLab’s October 21 advisory describes unauthenticated remote code execution under certain conditions through integer overflow during regular-expression compilation. Updating only GitLab Shell or Runner does not complete remediation of the CE/EE server.

Match the CVE to the product version first

This article covers CVE-2026-110264 from GitLab’s official notice, rated 10.0 under CVSS v3.1. Distinguish it from other GitLab CVEs released around the same time and similarly named Shell components. The GitLab-authored CVE record records the same affected ranges and fix thresholds.

GitLab CE/EE branch First release fixing this CVE
18.11 18.11.13
19.0 19.0.10
19.1 19.1.9
19.2 19.2.9
19.3 19.3.6
19.4 19.4.3
19.5 19.5.1

The notice identifies versions from 7.0 before 18.11.13 and each listed branch before its first fixed release as affected. Checked on October 30, 2026, this table gives first-fix thresholds, not a frozen list of the latest versions to install. GitLab.com and GitLab Dedicated have separate adoption information in the notice; do not apply Self-Managed upgrade instructions indiscriminately to those services.

Compare a declared version string offline

Parse a stable release version and compare its branch threshold numerically while leaving deployment unverified

The diagram follows the comparison code below. It validates input before comparing registered branches. Older affected branches require an upgrade path; branches outside the table remain unknown. No result authenticates a server’s state or patch provenance.

With Python 3.11 or later, save this file in a new directory. It assists with numeric comparison of official upstream CE/EE release versions without network requests, service discovery or exploitation. It accepts forms such as 19.5.1, 19.5.1-ee and 19.5.1-ee.0; it does not guess at prerelease, nightly or supplier-custom version formats.

release-threshold.py

import re
import sys

FIRST_FIX = {
    (18, 11): 13,
    (19, 0): 10,
    (19, 1): 9,
    (19, 2): 9,
    (19, 3): 6,
    (19, 4): 3,
    (19, 5): 1,
}
NUMBER = r"(0|[1-9][0-9]{0,2})"
VERSION = rf"{NUMBER}\.{NUMBER}\.{NUMBER}(?:-(?:ce|ee)(?:\.[0-9]{{1,3}})?)?"


def main(argv):
    match = re.fullmatch(VERSION, argv[1]) if len(argv) == 2 else None
    if match is None:
        print("usage: release-threshold.py VERSION (stable CE/EE release format)", file=sys.stderr)
        return 2
    major, minor, patch = map(int, match.groups())
    branch = (major, minor)
    if branch in FIRST_FIX:
        baseline = f"{major}.{minor}.{FIRST_FIX[branch]}"
        state = "met" if patch >= FIRST_FIX[branch] else "below"
        status = 0 if state == "met" else 1
    elif (7, 0) <= branch < (18, 11):
        baseline, state, status = "upgrade-path-required", "below", 1
    else:
        baseline, state, status = "not-covered", "outside-table", 2
    print(f"release-threshold={state}")
    print(f"baseline={baseline}")
    print("deployment-and-release-provenance=not-verified")
    return status


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
python3 release-threshold.py 19.5.1-ee.0

The local run returned this output and exit status 0.

release-threshold=met
baseline=19.5.1
deployment-and-release-provenance=not-verified

Status 0 means only that the supplied numbers meet this CVE’s published fix threshold. Status 1 means below the published threshold; status 2 means an unsupported format or a branch outside the table. It does not check that the release exists, the package is official or any node runs it. Backports and custom builds require separate supplier patch evidence.

Connect installation evidence to running adoption

The official maintenance documentation describes gathering GitLab, Ruby and component information with sudo gitlab-rake gitlab:env:info for Linux packages or bundle exec rake gitlab:env:info RAILS_ENV=production for source installations. On multi-node deployments, run it on nodes hosting Rails. Output can include internal paths and addresses, so keep it in restricted operational records.

These commands were not executed against a production server here. During actual remediation, connect the information to full package revisions, deployed image digests and each web/background node, then verify adoption across all targets after upgrading. One HTTP banner or another node’s command output is not evidence for the entire deployment.

Choose a current patch and finish migrations

Follow the official upgrade path from the installed version, allowing background migrations to finish at every required stop before proceeding. An old installation may not support jumping directly to the highest version in the table. Plan backup/recovery, extension compatibility, downtime and multi-node procedures together.

Distinguish first fixes from current patches. The October 29 patch notice lists later releases including 19.5.3 and 19.4.5, along with some database migrations, and explicitly says 19.5.2 and 19.4.4 were skipped. The script does not query a release catalog, so it performs numeric comparison even on those strings. Always select the actual installation candidate from official distribution records.

After upgrading, check running versions, migration completion, normal login, repository access and job processing separately. The advisory’s Onigmo worker-crash and Org-mode render-error-burst detections are investigation leads; neither alone proves or excludes compromise. Preserve logs, process and deployment evidence and investigate separately if compromise is suspected.

Java certificate remediation from the same period is a separate issue. For build and integration services using a JDK, also read eMudhra and JVM trust-store inspection.

Discussion

View on GitHub ↗