This is a loaded nail gun locked in a shed, not a grenade rolling across your network
CVE-2026-2876 is a stack-based buffer overflow in parse_macfilter_rule behind the /goform/setBlackRule handler on Tenda A18 firmware 15.13.07.13. The bug is triggered by an oversized deviceList parameter and the published CVSS vector marks it as PR:L, so this is not an unauthenticated internet spray-and-pray bug; the attacker needs access to the device's management plane and some level of valid session or credentials first.
The vendor's 8.8/HIGH score is fair in a lab because memory corruption on a network device can mean full device compromise. In real enterprise environments, though, this is a downgrade to MEDIUM because the attack chain is cramped: it targets a discontinued consumer Wi‑Fi extender, requires authenticated access, typically lives on a local management interface, has no KEV listing, and carries a very low EPSS.
4 steps from start to impact.
Reach the extender management UI
re.tenda.cn or 192.168.0.254 per the user guide. Practical weaponization here usually starts with a browser, curl, or Burp Suite to confirm the device model and endpoint structure before any exploit traffic is sent.- A Tenda A18 is actually deployed
- The attacker has layer-3 reachability to the management interface
- The management UI is enabled and reachable from the attacker's segment
- This is a consumer repeater, not a common enterprise-standard platform
- Management is usually local/LAN-side, not broadly internet-exposed
- Many enterprises simply do not have this product in managed inventory
Obtain authenticated access
- Valid login/session to the A18 management UI
- Ability to submit configuration requests after authentication
- This is already post-initial-access behavior
- MFA is uncommon on IoT gear, but network segmentation and admin workstation controls often block casual access
- Credentialed access narrows the exposed population sharply
Send the oversized deviceList payload
curl POST, the attacker submits a crafted request to /goform/setBlackRule with a maliciously large deviceList value. The public disclosure on GitHub documents this exact attack surface and associated proof material.- Firmware version is 15.13.07.13
- The vulnerable handler is present and callable after login
- The attacker can send crafted POST bodies
- Exact firmware matching matters; this is not an all-versions class break
- Router UI endpoint names and required parameters can vary across hardware or regional builds
- Exploit reproduction may require trial and error even with a public disclosure
/goform/setBlackRule; most commodity scanners will miss this unless they know the exact endpoint.Crash or potentially seize control of the device
parse_macfilter_rule, which can at minimum produce a denial of service and may permit code execution on the embedded device depending on build protections and exploit reliability. Weaponized tooling here is usually custom Python, replayed HTTP requests, or a manually tuned proof of concept rather than mature framework support.- The crafted payload survives input parsing to reach the vulnerable copy path
- The target build is exploitable in practice, not just crashable
- Embedded exploit reliability is often weaker than desktop/server RCE marketing suggests
- A watchdog reboot may turn this into a noisy crash instead of stable foothold
- Impact is confined to a single repeater unless the attacker can pivot from it
The supporting signals.
| In-the-wild status | No confirmed active exploitation found in the sources reviewed, and not listed in CISA KEV as of 2026-05-30. |
|---|---|
| Public PoC / exploit material | Yes, public disclosure exists: GitHub issue master-abc/cve#38 includes proof material for the /goform/setBlackRule + deviceList overflow path. |
| EPSS | 0.00101 (~0.10% 30-day exploitation probability) from the user-provided intel; that is very low and aligns with the lack of exploitation evidence. |
| KEV status | No. Not present in the CISA Known Exploited Vulnerabilities Catalog as checked on 2026-05-30. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — severe *if* reached, but PR:L is the decisive brake because it makes this a credentialed/post-access bug. |
| Affected versions | Tenda A18 firmware 15.13.07.13. Current public records do not show a broad version range; this appears to be an exact-version hit. |
| Fixed version | No authoritative fixed build located in vendor-facing sources reviewed. Tenda's site shows A18 is discontinued/retired, which raises the possibility that replacement is more realistic than patching. |
| Exposure / scanning reality | No CVE-specific GreyNoise/Censys/Shodan telemetry located in reviewed sources. The device is a local-managed Wi‑Fi extender, so internet-scale exposure is likely much lower than for enterprise firewalls or VPNs. |
| Disclosure timeline | GitHub issue opened 2026-02-09; NVD/CNA publication on 2026-02-21; NVD last modified 2026-02-23. |
| Researcher / source of record | CNA is VulDB; public exploit reference points to GitHub user 942384053 via issue #38 in master-abc/cve. |
noisgate verdict.
The single biggest reason this lands in MEDIUM is the authenticated-access requirement on a device that is usually managed locally, which makes exploitation inherently post-access rather than a true perimeter break. That narrowing effect matters more than the theoretical full-CIA impact on one repeater.
Why this verdict
- Down from 8.8 because
PR:Lmeans this is not pre-auth internet RCE; the attacker already needs credentials or an authenticated session. - Down again because attacker position is usually internal/LAN-side; Tenda A18 management is typically local, which implies either prior foothold or insider reachability.
- Down again because exposure population is small and odd for enterprises; this is a discontinued consumer Wi‑Fi extender, not a broadly deployed enterprise control plane.
- Down again because the affected set appears narrow; public records point to the exact build
15.13.07.13, not a sweeping multi-year affected range. - No upward pressure from threat intel; there is public proof material, but no KEV entry, no verified active exploitation, and EPSS is very low.
Why not higher?
If this were unauthenticated and commonly exposed on the WAN, the score would jump fast because a memory corruption bug on a network appliance can be takeover-grade. But stacking the real-world friction points together — local management reachability, required auth, narrow versioning, low deployment prevalence, and no exploitation evidence — keeps it out of HIGH.
Why not lower?
This is still a remotely reachable memory corruption flaw in network-device firmware, not a cosmetic info leak. Once an attacker has management access, the impact on that device can be serious, and public exploit material means defenders should not dismiss it as purely theoretical.
What to do — in priority order.
- Isolate management access — Put A18 management behind a dedicated admin VLAN or management ACLs so only approved jump hosts can reach it. For a MEDIUM verdict there is no noisgate mitigation SLA, so do this in the normal network-hardening cycle while keeping the asset inside the 365-day remediation window.
- Kill shadow IT extenders — Sweep for consumer repeaters and remove or formally onboard them, because the biggest risk amplifier here is unmanaged local admin exposure. With no mitigation SLA for MEDIUM, prioritize this through regular asset governance and complete replacement or remediation within 365 days.
- Rotate device credentials — Reset any reused or weak admin passwords and ensure the credentials differ from Wi‑Fi passphrases or shared helpdesk passwords. This directly attacks the
PR:Lprerequisite and should be folded into standard credential hygiene before the 365-day remediation deadline. - Block user VLANs from admin endpoints — Prevent routine workstation segments from reaching
192.168.0.254,re.tenda.cn, or equivalent device-admin addresses. That turns a credentialed bug into a much harder two-hop operation and is an effective compensating control while you work the 365-day remediation plan. - Prefer replacement over indefinite exception — Because the vendor site marks A18 as retired and no clear fixed version was located, treat any surviving A18s as lifecycle debt. For MEDIUM, there is no mitigation SLA — document, constrain, and replace inside the 365-day remediation window.
- A generic perimeter WAF does not help much if the web UI is only reachable on the inside; the real problem is internal admin-plane access.
- EDR on user endpoints does not protect the repeater itself; this is firmware-level attack surface on an embedded device.
- Blocking only inbound internet traffic is not enough if internal users or compromised hosts can still browse to the admin interface.
- Assuming 'not in KEV' means 'safe to ignore' is wrong; KEV absence lowers urgency, but it does not erase a credentialed device-compromise path.
Crowdsourced verification payload.
Run this on an auditor workstation or management jump box, not on the repeater itself. Invoke it as python3 check_tenda_a18_cve_2026_2876.py --model A18 --firmware 15.13.07.13 if you already know inventory data, or try python3 check_tenda_a18_cve_2026_2876.py --url http://192.168.0.254/ for a best-effort unauthenticated check; no elevated privileges are required.
#!/usr/bin/env python3
# check_tenda_a18_cve_2026_2876.py
# Non-destructive checker for CVE-2026-2876
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN / insufficient evidence
import argparse
import re
import sys
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
VULN_MODEL = 'A18'
VULN_FW = '15.13.07.13'
TIMEOUT = 5
def verdict(msg, code):
print(msg)
sys.exit(code)
def normalize_model(model):
return model.strip().upper() if model else None
def normalize_fw(fw):
return fw.strip() if fw else None
def check_inventory(model, firmware):
model = normalize_model(model)
firmware = normalize_fw(firmware)
if model != VULN_MODEL:
verdict(f'PATCHED: model {model} is not {VULN_MODEL}', 0)
if firmware == VULN_FW:
verdict(f'VULNERABLE: {VULN_MODEL} firmware {VULN_FW} matches CVE-2026-2876 affected version', 1)
if firmware:
verdict(f'PATCHED: {VULN_MODEL} firmware {firmware} does not match affected version {VULN_FW}', 0)
verdict('UNKNOWN: model supplied but firmware version missing', 2)
def fetch_url(url):
req = Request(url, headers={'User-Agent': 'noisgate-cve-check/1.0'})
with urlopen(req, timeout=TIMEOUT) as resp:
content_type = resp.headers.get('Content-Type', '')
body = resp.read(65536).decode('utf-8', errors='ignore')
return content_type, body
def extract_version(text):
patterns = [
r'15\.13\.07\.13',
r'firmware[^\n\r:]{0,30}(\d+\.\d+\.\d+\.\d+)',
r'version[^\n\r:]{0,30}(\d+\.\d+\.\d+\.\d+)',
r'v?(\d+\.\d+\.\d+\.\d+)'
]
for pat in patterns:
m = re.search(pat, text, flags=re.IGNORECASE)
if m:
if m.group(0) == VULN_FW:
return VULN_FW
if m.lastindex:
return m.group(1)
return m.group(0)
return None
def check_url(url):
try:
_, body = fetch_url(url)
except HTTPError as e:
verdict(f'UNKNOWN: HTTP error while fetching {url}: {e.code}', 2)
except URLError as e:
verdict(f'UNKNOWN: connection error while fetching {url}: {e.reason}', 2)
except Exception as e:
verdict(f'UNKNOWN: unexpected error while fetching {url}: {e}', 2)
body_upper = body.upper()
if 'TENDA' not in body_upper and 'A18' not in body_upper and 'RE.TENDA.CN' not in body_upper:
verdict('UNKNOWN: target did not clearly identify as a Tenda A18 management page', 2)
version = extract_version(body)
if version == VULN_FW:
verdict(f'VULNERABLE: discovered firmware version {VULN_FW} on apparent Tenda A18 page', 1)
elif version:
verdict(f'PATCHED: apparent Tenda A18 page exposes firmware version {version}, not affected version {VULN_FW}', 0)
else:
verdict('UNKNOWN: page looks like Tenda admin UI, but firmware version was not exposed unauthenticated', 2)
def main():
parser = argparse.ArgumentParser(description='Check Tenda A18 exposure to CVE-2026-2876')
parser.add_argument('--model', help='Device model from inventory, e.g. A18')
parser.add_argument('--firmware', help='Firmware version from inventory, e.g. 15.13.07.13')
parser.add_argument('--url', help='Base URL of suspected device, e.g. http://192.168.0.254/')
args = parser.parse_args()
if args.model:
check_inventory(args.model, args.firmware)
if args.url:
check_url(args.url)
verdict('UNKNOWN: provide either --model/--firmware or --url', 2)
if __name__ == '__main__':
main()
If you remember one thing.
Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.