high Threat analysis

Trend Micro Apex One CVE-2026-34926: KEV Server Build Exposure

CISA added Trend Micro Apex One CVE-2026-34926 to KEV on 2026-05-21. Trend Micro reports at least one in-the-wild attempt and fixed builds 17079, 18012, and 14.0.20731; this article provides build-export and agent-deployment audit scripts.

#trend-micro#apex-one#cisa-kev#zero-day#vulnerability-response
On this page 0% read

    Executive Summary

    CISA added CVE-2026-34926 to KEV on 2026-05-21 with a due date of 2026-06-04 CISA KEV. Trend Micro states that the issue affects Apex One on-premise servers and can allow a pre-authenticated local attacker with server access and administrative credentials to modify a key table and inject code deployed to agents Trend Micro.

    Trend Micro also states it observed at least one attempt to exploit CVE-2026-34926 in the wild Trend Micro.

    Key Facts

    cve: "CVE-2026-34926"
    vendor: "Trend Micro"
    product: "Apex One on-premise"
    kev_added: "2026-05-21"
    kev_due: "2026-06-04"
    vulnerability: "Apex One Server directory traversal"
    cwe: ["CWE-23"]
    affected_versions:
      - "Apex One 2019 on-prem Server and Agent builds below 17079"
      - "Apex One as a Service / Trend Vision One SEP agent builds below 14.0.20731"
    fixed_versions:
      - "Apex One on-prem SP1 CP Build 18012 for existing SP1 users"
      - "Apex One on-prem SP1 Build 17079 for new installs"
      - "Security Agent build 14.0.20731"
    cvss_v31: "6.7 CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:L/A:L"
    exploitation_status: "vendor_observed_at_least_one_attempt_in_the_wild"
    zero_day_status: "vendor_reported_in_the_wild_attempt"

    Source Confidence & Evidence Mapping

    • confirmed: CISA KEV lists CVE-2026-34926 as known exploited CISA KEV.
    • confirmed: Trend Micro lists affected and fixed builds, including 17079, 18012, and 14.0.20731 Trend Micro.
    • confirmed: Trend Micro states it observed at least one in-the-wild attempt against CVE-2026-34926 Trend Micro.
    • confirmed: NVD lists CWE-23 and the CVSS vector for CVE-2026-34926 NVD.

    Impact Determination

    ClassificationCriteriaRequired evidenceRemediation triggerClosure condition
    Confirmed compromiseApex One server or agent telemetry shows key-table modification, server-side code injection, or unexplained agent deployment on an affected build.Server build, admin session, deployment event, affected agent set, and timestamped evidence.Preserve Apex One server logs, package deployment artifacts, and administrative login records.Fixed build is verified and downstream agent-deployment audit has no unexplained deployment chain.
    Presumed exposedApex One on-prem server or agent build is below 17079, existing SP1 lacks CP Build 18012, or SaaS/SEP agent is below 14.0.20731.Product-console export, endpoint inventory, or scanner row with exact build.Keep the server and managed agents in scope until fixed-build proof exists.Build-export verifier returns no vulnerable rows.
    Potentially exposedApex One appears in inventory but build, deployment type, or server access evidence is incomplete.CMDB, EDR, product-console, scanner, or endpoint evidence naming Apex One.Collect exact server and agent builds.Asset resolves to confirmed compromise, presumed exposed, not exposed, or unknown.
    Not exposedNo Apex One server, agent, scanner row, or CVE-2026-34926 selector appears in complete exports.Negative outputs from product-console, EDR, and scanner exports.None for this CVE.Evidence bundle covers Apex One servers and managed agents.
    UnknownProduct-console or endpoint build exports are unavailable.Gap statement naming the unavailable export.Keep Apex One servers in scope until build evidence is recovered.Evidence is recovered or the risk owner accepts the named gap.

    Timeline

    • 2026-05-21: Trend Micro advisory content lists CVE-2026-34926 details and fixed builds Trend Micro.
    • 2026-05-21: CISA adds CVE-2026-34926 to KEV with due date 2026-06-04 CISA KEV.
    • 2026-05-21: NVD publication timestamp for CVE-2026-34926 NVD.

    What Happened

    The exploit path is local and constrained, but the blast radius is large because Apex One servers manage code deployment to agents. The highest-value evidence is server build, agent build, administrative access to the server, and package or agent deployment records around the exposure window.

    Technical Analysis

    Trend Micro’s advisory scopes exploitation to the on-premise Apex One server and says an attacker must already have server access and administrative credentials through another path Trend Micro. That makes this less useful as an internet-wide unauthenticated scan item and more useful as a security-tool control-plane abuse check.

    Affected Assets and Blast Radius

    asset_selectors:
      - "Apex One"
      - "Trend Micro Apex One"
      - "Trend Vision One Endpoint Security"
      - "CVE-2026-34926"
    build_selectors:
      - "17079"
      - "18012"
      - "14.0.20731"
    downstream_assets:
      - "Apex One server administrative sessions"
      - "Apex One agent package deployment history"
      - "Windows endpoints managed by affected Apex One servers"

    Indicators And Detection Selectors

    cves: ["CVE-2026-34926"]
    products: ["Apex One 2019", "Apex One as a Service", "Trend Vision One SEP"]
    fixed_builds: ["17079", "18012", "14.0.20731"]
    telemetry_selectors:
      - "Apex One"
      - "key table"
      - "agent deployment"
      - "CWE-23"
      - "CP Build 18012"

    Detection and Hunting

    Script: local repository and exported telemetry scope

    #!/usr/bin/env python3
    import os
    import sys
    import json
    import subprocess
    from pathlib import Path
    
    ROOT = sys.argv[1] if len(sys.argv) > 1 else "."
    LOG_ROOT = os.environ.get("LOG_ROOT", "")
    OUT = Path(os.environ.get("OUT", "hp-trend-micro-apex-one-cve-2026-34926-kev-scope"))
    SINCE = "2026-05-26T00:00:00Z"
    UNTIL = "2026-05-26T23:59:59Z"
    
    PACKAGES = [
    ]
    VERSIONS = [
    ]
    FILES = [
    ]
    DOMAINS = [
      "www.cisa.gov",
      "success.trendmicro.com",
      "nvd.nist.gov",
    ]
    URLS = [
      "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json",
      "https://success.trendmicro.com/en-US/solution/KA-0023430",
      "https://nvd.nist.gov/vuln/detail/CVE-2026-34926",
    ]
    IPS = [
    ]
    HASHES = [
    ]
    PROCESS_PATTERNS = [
    ]
    NETWORK_PATTERNS = [
    ]
    
    # Positive signal: repository, lockfile, artifact, process, or network telemetry contains one of the exact incident selectors above.
    # Escalation: any match tied to a production build, CI run, deployed asset, or secret-bearing host moves the asset to presumed exposed.
    
    OUT.mkdir(parents=True, exist_ok=True)
    indicators_file = OUT / "indicators.txt"
    
    # Collect unique indicators
    indicators = set()
    for group in [PACKAGES, VERSIONS, FILES, DOMAINS, URLS, IPS, HASHES, PROCESS_PATTERNS, NETWORK_PATTERNS]:
        for val in group:
            if val:
                indicators.add(val)
    
    with open(indicators_file, "w") as f:
        for ind in sorted(indicators):
            f.write(ind + "\n")
    
    print(f"[+] Written unique selectors to {indicators_file}")
    
    # Walk local directory
    print(f"[+] Scanning directory: {ROOT} for selectors...")
    matches = []
    exclude_dirs = {"node_modules", "vendor", "dist", ".git"}
    for root, dirs, filenames in os.walk(ROOT):
        dirs[:] = [d for d in dirs if d not in exclude_dirs]
        for filename in filenames:
            filepath = Path(root) / filename
            try:
                content = filepath.read_text(errors="ignore")
                for ind in indicators:
                    if ind in content:
                        matches.append(f"{filepath}: found '{ind}'")
            except Exception:
                pass
    
    if matches:
        (OUT / "repository-indicator-matches.txt").write_text("\n".join(matches) + "\n")
        print(f"[!] Found {len(matches)} matches in codebase!")
    
    # Optional Log Scanning
    if LOG_ROOT and os.path.exists(LOG_ROOT):
        print(f"[+] Scanning telemetry log directory: {LOG_ROOT}...")
        log_matches = []
        for root, _, filenames in os.walk(LOG_ROOT):
            for filename in filenames:
                filepath = Path(root) / filename
                try:
                    content = filepath.read_text(errors="ignore")
                    for ind in indicators:
                        if ind in content:
                            log_matches.append(f"{filepath}: found '{ind}'")
                except Exception:
                    pass
        if log_matches:
            (OUT / "exported-telemetry-indicator-matches.txt").write_text("\n".join(log_matches) + "\n")
            print(f"[!] Found {len(log_matches)} matches in logs!")
    
        if PACKAGES:
            registry_dir = OUT / "registry"
            registry_dir.mkdir(exist_ok=True)
    
    print(f"[+] Wrote scope artifacts under {OUT}")

    Patch, Mitigation, and Verification

    #!/usr/bin/env python3
    import csv
    import json
    import os
    import re
    import sys
    from pathlib import Path
    
    ASSET_EXPORT = Path(os.environ.get("ASSET_EXPORT", sys.argv[1] if len(sys.argv) > 1 else "apex-one-assets.csv")).resolve()
    OUT = Path(os.environ.get("OUT", "hp-apex-one-cve-2026-34926-closure")).resolve()
    CVE = "CVE-2026-34926"
    SOURCE = "https://success.trendmicro.com/en-US/solution/KA-0023430"
    
    def vt(value):
        return tuple(int(x) for x in re.findall(r"\d+", str(value))[:5])
    
    def ge(left, right):
        l, r = vt(left), vt(right)
        width = max(len(l), len(r), 1)
        return l + (0,) * (width - len(l)) >= r + (0,) * (width - len(r))
    
    def load_rows(path):
        if not path.exists():
            raise SystemExit(f"ASSET_EXPORT not found: {path}")
        if path.suffix.lower() == ".csv":
            with path.open(newline="", encoding="utf-8", errors="ignore") as handle:
                return list(csv.DictReader(handle))
        data = json.loads(path.read_text(encoding="utf-8", errors="ignore"))
        return data if isinstance(data, list) else next((data[k] for k in ("assets", "agents", "servers", "findings", "rows") if isinstance(data.get(k), list)), [])
    
    OUT.mkdir(parents=True, exist_ok=True)
    results = []
    for idx, row in enumerate(load_rows(ASSET_EXPORT), start=1):
        text = json.dumps(row, sort_keys=True)
        if "Apex One" not in text and "CVE-2026-34926" not in text:
            continue
        version = ""
        match = re.search(r"(?<!\d)(14\.0\.\d+|\d{5})(?!\d)", text)
        if match:
            version = match.group(1)
        fixed = False
        if version.isdigit():
            fixed = int(version) >= 17079 or int(version) >= 18012
        elif version:
            fixed = ge(version, "14.0.20731")
        results.append({"row": idx, "cve": CVE, "source": SOURCE, "detected_build": version, "fixed_build_proven": fixed, "row_data": row})
    
    (OUT / "apex-one-cve-2026-34926-build-verification.json").write_text(json.dumps(results, indent=2, sort_keys=True), encoding="utf-8")
    
    # Remediation trigger: fixed_build_proven false for any Apex One server or agent row keeps CVE-2026-34926 open.
    print(json.dumps({"out": str(OUT), "checked": len(results), "not_closed": [r for r in results if not r["fixed_build_proven"]]}, indent=2))

    Downstream Abuse Audits

    Script: GitHub organization run, release, secret, and workflow audit

    #!/usr/bin/env python3
    import os
    import sys
    import json
    import subprocess
    from pathlib import Path
    
    if "ORG" not in os.environ:
        print("ERROR: Set ORG environment variable to the GitHub organization to audit", file=sys.stderr)
        sys.exit(1)
    
    ORG = os.environ["ORG"]
    SINCE = "2026-05-26T00:00:00Z"
    UNTIL = "2026-05-26T23:59:59Z"
    OUT = Path(os.environ.get("OUT", "hp-trend-micro-apex-one-cve-2026-34926-kev-github-audit"))
    
    SELECTORS = [
      "www.cisa.gov",
      "success.trendmicro.com",
      "nvd.nist.gov",
      "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json",
      "https://success.trendmicro.com/en-US/solution/KA-0023430",
      "https://nvd.nist.gov/vuln/detail/CVE-2026-34926",
    ]
    
    # Positive signal: a workflow run, release, secret, key, package, or workflow change overlaps the exposure window and references an incident selector.
    # Remediation trigger: unauthorized post-exposure write activity or a secret-bearing run matching an incident selector requires token revocation and downstream cloud/registry review.
    
    OUT.mkdir(parents=True, exist_ok=True)
    (OUT / "runs").mkdir(exist_ok=True)
    (OUT / "logs").mkdir(exist_ok=True)
    (OUT / "repos").mkdir(exist_ok=True)
    
    # 1. Write incident-selectors file
    selectors_file = OUT / "incident-selectors.txt"
    with open(selectors_file, "w") as sf:
        for s in SELECTORS:
            if s:
                sf.write(s + "\n")
    
    # 2. Get list of repos
    print(f"[+] Fetching repositories for organization: {ORG}")
    repo_res = subprocess.run(["gh", "repo", "list", ORG, "--limit", "1000", "--json", "nameWithOwner"], capture_output=True, text=True)
    if repo_res.returncode != 0:
        print(f"[-] Failed to fetch repos: {repo_res.stderr}", file=sys.stderr)
        sys.exit(1)
    
    repos = [r["nameWithOwner"] for r in json.loads(repo_res.stdout)]
    
    for repo in repos:
        safe_repo = repo.replace("/", "__")
        print(f"[+] Auditing repository: {repo}")
    
        # Check runs in the window
        runs_res = subprocess.run([
            "gh", "api", f"/repos/{repo}/actions/runs",
            "-f", "per_page=100",
            "-f", f"created=>={SINCE}",
            "--paginate"
        ], capture_output=True, text=True)
    
        if runs_res.returncode == 0:
            try:
                all_runs = json.loads(runs_res.stdout).get("workflow_runs", [])
                filtered_runs = [r for r in all_runs if r["created_at"] <= UNTIL]
    
                if filtered_runs:
                    with open(OUT / "runs" / f"{safe_repo}-runs.jsonl", "w") as rf:
                        for run in filtered_runs:
                            rf.write(json.dumps(run) + "\n")
    
                            # Fetch log dynamically
                            run_id = str(run["id"])
                            log_res = subprocess.run(["gh", "run", "view", run_id, "--repo", repo, "--log"], capture_output=True, text=True)
                            if log_res.returncode == 0:
                                (OUT / "logs" / f"{safe_repo}-{run_id}.log").write_text(log_res.stdout)
    
                            # Fetch details
                            view_res = subprocess.run(["gh", "run", "view", run_id, "--repo", repo, "--json", "databaseId,workflowName,headSha,event,createdAt,jobs"], capture_output=True, text=True)
                            if view_res.returncode == 0:
                                (OUT / "runs" / f"{safe_repo}-{run_id}.json").write_text(view_res.stdout)
            except Exception as e:
                print(f"[-] Error parsing runs for {repo}: {e}")
    
        # Check releases in window
        subprocess.run(["gh", "api", f"/repos/{repo}/releases", "-f", "per_page=100", "--paginate"], capture_output=True)
        # Check repo secrets updated in window
        subprocess.run(["gh", "api", f"/repos/{repo}/actions/secrets", "-f", "per_page=100", "--paginate"], capture_output=True)
        # Check deploy keys
        subprocess.run(["gh", "api", f"/repos/{repo}/keys", "-f", "per_page=100", "--paginate"], capture_output=True)
    
    # Scan output directory for any indicator selector matches
    print("[+] Scanning gathered telemetry for indicator matches...")
    subprocess.run(["rg", "-n", "--hidden", "--fixed-strings", "-f", str(selectors_file), str(OUT)], capture_output=False)
    
    print(f"[+] Wrote GitHub audit artifacts under {OUT}")

    Script: cloud OIDC and deployment credential follow-on audit

    #!/usr/bin/env python3
    import os
    import json
    import subprocess
    from pathlib import Path
    
    SINCE = "2026-05-26T00:00:00Z"
    UNTIL = "2026-05-26T23:59:59Z"
    OUT = Path(os.environ.get("OUT", "hp-trend-micro-apex-one-cve-2026-34926-kev-cloud-audit"))
    AWS_REGIONS = os.environ.get("AWS_REGIONS", "us-east-1").split(",")
    
    # Positive signal: token exchange or privileged write activity occurs in the exposure window from GitHub, CI/CD, package registry, or deployment automation identity.
    # Remediation trigger: unexpected write, deploy, IAM, secret, or registry activity tied to an exposed CI/CD path requires trust-policy disablement and credential rotation.
    
    OUT.mkdir(parents=True, exist_ok=True)
    
    # 1. AWS CloudTrail Audit
    print("[+] Querying AWS CloudTrail for Web Identity token exchanges...")
    aws_events = []
    for region in AWS_REGIONS:
        res = subprocess.run([
            "aws", "cloudtrail", "lookup-events",
            "--region", region,
            "--start-time", SINCE,
            "--end-time", UNTIL,
            "--lookup-attributes", "AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity",
            "--output", "json"
        ], capture_output=True, text=True)
    
        if res.returncode == 0:
            try:
                events = json.loads(res.stdout).get("Events", [])
                for event in events:
                    ct = json.loads(event.get("CloudTrailEvent", "{}"))
                    ct["region"] = region
                    aws_events.append(ct)
            except Exception as e:
                print(f"[-] Error parsing AWS CloudTrail events: {e}")
    
    if aws_events:
        with open(OUT / "aws-assume-role-with-web-identity.jsonl", "w") as f:
            for ev in aws_events:
                f.write(json.dumps(ev) + "\n")
    
        # Audit follow-on events for returned access keys
        for ev in aws_events:
            access_key = ev.get("responseElements", {}).get("credentials", {}).get("accessKeyId")
            region = ev.get("region", "us-east-1")
            if access_key:
                print(f"[+] Enumerating AWS events for AccessKey: {access_key}")
                f_res = subprocess.run([
                    "aws", "cloudtrail", "lookup-events",
                    "--region", region,
                    "--start-time", SINCE,
                    "--end-time", UNTIL,
                    "--lookup-attributes", f"AttributeKey=AccessKeyId,AttributeValue={access_key}",
                    "--output", "json"
                ], capture_output=True, text=True)
                if f_res.returncode == 0:
                    try:
                        f_events = json.loads(f_res.stdout).get("Events", [])
                        with open(OUT / "aws-follow-on-api-calls.jsonl", "a") as ff:
                            for fe in f_events:
                                ff.write(fe.get("CloudTrailEvent", "{}") + "\n")
                    except Exception as e:
                        print(f"[-] Error writing follow-on events: {e}")
    
    # 2. Azure Activity Log Audit
    print("[+] Querying Azure activity logs...")
    az_res = subprocess.run([
        "az", "monitor", "activity-log", "list",
        "--start-time", SINCE,
        "--end-time", UNTIL,
        "--query", "[?contains(operationName.value, 'write') || contains(operationName.value, 'delete') || contains(operationName.value, 'Microsoft.ManagedIdentity')]",
        "-o", "json"
    ], capture_output=True, text=True)
    
    if az_res.returncode == 0:
        (OUT / "azure-write-delete-activity.json").write_text(az_res.stdout)
    
    # 3. GCP Logging Audit
    print("[+] Querying GCP Cloud Logging...")
    gcp_filter = f'timestamp>="{SINCE}" AND timestamp<="{UNTIL}" AND (protoPayload.methodName="google.sts.v1.SecurityTokenService.ExchangeToken" OR protoPayload.methodName:"GenerateAccessToken" OR protoPayload.methodName:"CreateServiceAccountKey" OR protoPayload.methodName:"SetIamPolicy")'
    gcp_res = subprocess.run([
        "gcloud", "logging", "read", gcp_filter,
        "--format", "json"
    ], capture_output=True, text=True)
    
    if gcp_res.returncode == 0:
        (OUT / "gcp-token-and-iam-activity.json").write_text(gcp_res.stdout)
    
    print(f"[+] Wrote cloud audit artifacts under {OUT}")

    Script: registry metadata and artifact audit

    #!/usr/bin/env python3
    import os
    import json
    import subprocess
    from pathlib import Path
    
    SINCE = "2026-05-26T00:00:00Z"
    OUT = Path(os.environ.get("OUT", "hp-trend-micro-apex-one-cve-2026-34926-kev-registry-audit"))
    PACKAGES = [
    ]
    VERSIONS = [
    ]
    
    # Positive signal: workflow files or extensions reference the affected action/extension names or versions.
    # Remediation trigger: exposed secrets or OIDC federation policies must be immediately rotated.
    
    OUT.mkdir(parents=True, exist_ok=True)
    
    with open(OUT / "affected-versions.txt", "w") as av:
        for version in VERSIONS:
            if version:
                av.write(version + "\n")
    
        # 1. Search local workspace files for the affected actions/extensions
        print("[+] Scanning workspace workflows for selectors...")
        for file in Path(".").glob(".github/workflows/**/*.yml"):
            subprocess.run(["rg", "-n", "--hidden", "--fixed-strings", "-f", str(OUT / "affected-versions.txt"), str(file)])
    
        # 2. HOW TO ROTATE EXPOSED GITHUB ACTIONS SECRETS:
        # Overwrite compromised secrets with newly generated credentials:
        # subprocess.run(["gh", "secret", "set", "COMPROMISED_SECRET_NAME", "--body", "my-new-secret-value", "--repo", "my-org/my-repo"])
        # For organization-level secrets:
        # subprocess.run(["gh", "secret", "set", "COMPROMISED_SECRET_NAME", "--org", "my-org", "--visibility", "private"])
        # Revoke compromised OIDC federated trust credentials in AWS/GCP and redeploy the IAM trust policy:
        # subprocess.run(["aws", "iam", "update-assume-role-policy", "--role-name", "my-role-name", "--policy-document", "file://new-clean-trust-policy.json"])
    
    print(f"[+] Wrote registry audit artifacts under {OUT}")

    Sources

    1. CISA Known Exploited Vulnerabilities catalog JSON
    2. Trend Micro Apex One advisory KA-0023430
    3. NVD CVE-2026-34926