Back to blog

CVE-2026-78174: how an unredacted session token in a diagnostic log turned a low-privileged WatchGuard Dimension admin into super admin

· · 19 min read

On August 27, 2026, WatchGuard published an advisory for a vulnerability in Dimension, its on-premises network visibility and management appliance, four days after reserving the identifier and after a private report from researcher Simone Paganessi. The verdict is short and unpleasant: any authenticated Dimension Administrator, the lowest management role on the box, can read a diagnostic log that contains the live session token of a logged-in Super Administrator, replay it, and take over the highest-privileged account on the appliance. The bug is tracked as CVE-2026-78174 and carries a CVSS v4.0 score of 9.3 (Critical). The striking part is not the score. It is that the entire attack is a read: no memory corruption, no injection, no crafted payload. The appliance simply wrote a secret into a place a less-trusted user was allowed to look.

This is a two-layered breakdown. The first part is for readers who need to decide quickly whether they have anything to do about this and what exactly that is. The second part dissects the flaw the way the researcher reconstructed it: what the diagnostic log records, why the session token ends up in it unredacted, and how a lower-privileged role converts a log line into full control of the appliance. The article closes by looking at how the Pragma Core platform addresses exactly the class of problem that made this possible, because the interesting thing about CVE-2026-78174 is not the specific log line, it is the pattern.


Part I. Executive breakdown

What happened

WatchGuard Dimension is the on-premises companion to WatchGuard's firewalls. Firebox appliances ship their logs to Dimension, and administrators use its web interface to search traffic, build reports, and manage device configuration from one place. Because it sees log data from an entire fleet of firewalls, Dimension is a high-value box: whoever controls it controls the visibility and, in many deployments, part of the management of the network's edge.

Dimension has more than one kind of administrator. A Super Administrator can do everything, including managing accounts. A plain Dimension Administrator is a lower tier, meant to operate the product without touching who is allowed in. The vulnerability collapses that boundary. Dimension keeps a diagnostic log in its web UI, the sort of verbose internal log a support engineer would use to troubleshoot. That log records the session identifiers of users who are logged in, and it records them in the clear. A session identifier is the secret string a browser presents on every request to prove "I am the person who already logged in." If you hold someone's valid session identifier, the server treats you as that person, no password required.

So the attack is almost embarrassingly direct. A low-privileged Dimension Administrator opens the diagnostic log, which their role is allowed to retrieve, waits for or notices that a Super Administrator is logged in, and copies that Super Administrator's session token (and the matching anti-CSRF token) straight out of the log. They then present those tokens to the appliance and are, for all practical purposes, the Super Administrator. From there they can open Access Management, create, alter, or delete any user or group, rewrite system-wide configuration, lock out the real administrators, and keep a foothold.

Who is affected

Component Status
WatchGuard Dimension 2.0 up to (but not including) 2.3.1 Vulnerable. Upgrade to 2.3.1.
WatchGuard Dimension 2.3.1 and later Patched. Not affected.

The affected range is wide: everything from 2.0 to just before 2.3.1. Dimension is an on-premises virtual appliance, typically run inside an organization's own VMware environment, so there is no silent cloud-side fix. Every instance is patched by its owner or it is not patched at all. WatchGuard states it is not aware of exploitation in the wild, and the modelled exploitation likelihood is low (EPSS around 0.3 percent), but both of those numbers reflect a bug published days ago with no public proof of concept, not a bug that is hard to abuse. The precondition, a second administrative account, is common in exactly the multi-admin, multi-tenant, managed-service deployments where Dimension is most useful.

Why this matters beyond WatchGuard

The specific product is WatchGuard Dimension, but the shape of the bug is one of the most common findings in application security, and one of the least glamorous. It has a name in the taxonomy: CWE-532, insertion of sensitive information into a log file, joined here by CWE-200, exposure of sensitive information to an unauthorized actor, and CWE-269, improper privilege management. In plain terms: a secret was written somewhere it should not have been, and someone who should not have been able to read that place could.

Every application that has sessions has session tokens, and almost every application has verbose or diagnostic logging that engineers turn on when something breaks. The moment those two features touch, the moment a token, a password, an API key, or an authorization header lands in a log, the security of that secret drops to the security of the log. If a lower-privileged role, a support tool, a log-shipping pipeline, or a third party can read the log, they can read the secret. This pattern shows up in web frameworks that log full request objects, in reverse proxies that log headers, in mobile apps that dump tokens to the console, and in appliances like this one. It is worth internalizing that "who can read this log" is an access-control decision with the same weight as "who can read this database."

Recommended actions

  1. Upgrade to Dimension 2.3.1 or later. This is the only complete fix; the earlier versions all write the token unredacted and there is no configuration flag that turns the behavior off.
  2. Treat any current sessions as potentially exposed and rotate. After patching, force re-authentication and, where possible, invalidate existing Super Administrator sessions, since a token that was already harvested from an old diagnostic log does not stop working just because you upgraded.
  3. Inventory who holds the Dimension Administrator role. The attack requires an authenticated lower-privileged account, so the real blast radius is "everyone with a Dimension login below Super Administrator." Reduce that list to who genuinely needs it.
  4. Review access to the diagnostic log and to any exported copies. Diagnostic logs are frequently downloaded and attached to support tickets or dropped into shared storage. A token in an exported log is exposed to everyone who can reach that file, not just live users.
  5. Audit for signs of misuse. Look for Super Administrator actions (account creation or changes, configuration edits) that do not line up with a known Super Administrator login, and for a Dimension Administrator retrieving the diagnostic log around the time a Super Administrator was active.
  6. Segment the management interface. Dimension's web UI should not be broadly reachable. Restricting who can even present a stolen token to the appliance limits what a leaked session buys an attacker.

Part II. Technical breakdown

The appliance and its trust model

WatchGuard Dimension is delivered as a 64-bit Linux virtual appliance (historically an OVA for VMware ESXi) with a PostgreSQL backend and a web application front end. Fireboxes and WatchGuard servers stream their log messages to it over an authenticated channel, and operators drive everything through the browser: dashboards, report generation, log search, and device management. Because it aggregates telemetry from the network edge, Dimension is a natural pivot point, and its own account model is the thing standing between "operator" and "owner of the box."

That account model is the trust boundary the bug lives on. Dimension distinguishes a Super Administrator, who can manage accounts and system configuration, from a Dimension Administrator, a role that can operate the product but is not supposed to be able to escalate to account management. The whole point of having two tiers is that giving someone the lower tier is supposed to be safe: you can let a junior operator or a tenant administrator run reports and watch traffic without handing them the keys. CVE-2026-78174 is a failure of that promise. It does not break the login. It breaks the assumption that the lower tier cannot reach the higher tier's credentials.

The relevant mechanism is session management. Like most web applications, Dimension authenticates a user once and then issues a session identifier that the browser returns on every subsequent request. Alongside it, the application uses an anti-CSRF token to ensure that state-changing requests originate from the real UI. Together, the session identifier and the CSRF token are enough to act as the logged-in user for the lifetime of that session. They are, functionally, bearer credentials: possession is authorization.

The vulnerability: a session token written to a log a lower role can read

The flaw is the combination of two design decisions that are each defensible alone and catastrophic together.

The first decision is that Dimension's web UI diagnostic log records the session identifier of logged-in users without redaction. Diagnostic logging is verbose by nature. To correlate what happened in a troubleshooting scenario, the code paths that handle requests log context about the current session, and here that context included the raw session identifier (and, in the account-takeover chain, the CSRF token) rather than a masked or hashed placeholder. Conceptually, the offending log call looks like the sort of line that exists in countless codebases:

// Illustrative reconstruction of the pattern, not WatchGuard source.
// Diagnostic path logs full session context to help support reproduce issues.
logger.debug("WebUI request user={} role={} sessionId={} csrfToken={} uri={}",
             user.getName(), user.getRole(),
             session.getId(),        // <-- raw, unredacted bearer credential
             session.getCsrfToken(), // <-- the second half of the takeover
             request.getRequestUri());

Nothing here throws an error. The value is valid, the log is doing precisely what it was told to do, and in isolation "log the session id so we can trace this request" reads like reasonable troubleshooting hygiene. The problem is that a session identifier is not diagnostic metadata. It is a live credential, and writing it verbatim is equivalent to writing the user's password to the log for as long as their session is valid.

The second decision is that the diagnostic log is retrievable by a Dimension Administrator, the lower-privileged role, and not gated to the Super Administrator alone. Again, on its own this is a normal choice: operators need logs to do their job, and "let administrators pull diagnostic output" is standard. Conceptually:

// Illustrative reconstruction of the pattern, not WatchGuard source.
@GET("/api/diagnostics/webui-log")
@RequiresRole(Role.DIMENSION_ADMIN)   // lower tier is enough to read it
public Response getDiagnosticLog() {
    return Response.ok(diagnosticLog.read()).build();
}

Neither line is a bug by itself. The vulnerability is entirely in their relationship: the log sink writes a high-value secret, and the access rule on that sink is set to a lower privilege than the secret it now contains. The token's confidentiality has quietly been downgraded from "Super Administrator only" to "any Dimension Administrator," and nobody re-evaluated the access rule when the sensitive value started flowing into the sink.

Root cause: confidentiality of a secret set by the weakest place it is written

The precise failure is a mismatch between the sensitivity of the data (a Super Administrator's live session credentials) and the access control on the container it was placed in (a diagnostic log readable by a lower role). A secret is only as protected as the most permissive location it is ever written to. Once the token appears in the diagnostic log, its effective protection is whatever guards that log, and that guard was set for "operational log data," not "bearer credentials for the highest account on the box."

There are two independent things that had to be true for this to be exploitable, and both were:

Remove either property, redact the token in the log, or restrict the log to the same tier as the token's owner, and the chain breaks. That both were present is why the CWE trio fits so cleanly: CWE-532 describes the token landing in the log, CWE-200 describes the wrong actor being able to read it, and CWE-269 describes the resulting collapse of the privilege boundary.

Exploitation: from a log read to full account takeover

The exploitation path needs no crafted input and no timing race beyond "a Super Administrator is logged in." The steps are ordinary HTTP.

First, the attacker, holding a Dimension Administrator account, retrieves the diagnostic log through the interface their role already permits:

# Authenticated as a low-privileged Dimension Administrator.
curl -s https://dimension.internal/api/diagnostics/webui-log \
     -b "sessionId=<attacker_own_session>" \
     -H "X-CSRF-Token: <attacker_own_csrf>" \
     -o webui-diagnostic.log

Second, they pull the Super Administrator's live session identifier and CSRF token out of the returned log. Because the values are unredacted, this is a search, not a decode:

grep -Eo 'role=SUPER_ADMIN[^\n]*sessionId=[A-Za-z0-9._-]+[^\n]*csrfToken=[A-Za-z0-9._-]+' \
     webui-diagnostic.log
# role=SUPER_ADMIN user=admin sessionId=6f2b...redacted... csrfToken=9ad1...redacted...

Third, they replay those tokens against a Super Administrator only endpoint, for example account management, presenting the harvested session and CSRF values as if they were their own:

# Now acting as the Super Administrator with the stolen bearer credentials.
curl -s https://dimension.internal/api/access-management/users \
     -b "sessionId=<stolen_super_admin_session>" \
     -H "X-CSRF-Token: <stolen_super_admin_csrf>" \
     -X POST \
     -d '{"username":"svc-backup","role":"SUPER_ADMIN","password":"<attacker_set>"}'

At that point the escalation is durable. Rather than relying on the borrowed session, which expires, the attacker uses the borrowed session once to create their own Super Administrator account (or promote their existing one). Now they have a persistent, first-class administrative identity. From there the advisory's impact list follows directly: read and modify Access Management, create, delete, or alter any user or group, change system-wide configuration, lock out the legitimate administrators, and retain full control of the appliance. The one borrowed request bootstraps permanent ownership.

It is worth stressing what is absent from this chain. There is no buffer to overflow, no injection to smuggle past a parser, no filter to evade. The appliance handed the credential to a user who asked for a log. Every request above is well-formed and, from the server's point of view, authorized. That is what makes this class of bug so easy to weaponize once known and so easy to miss in a scanner that is looking for malformed input.

Affected versions

There is no partial mitigation short of the upgrade in the advisory. The remediation in 2.3.1 addresses the behavior at the source, so the correct action is to move to that release rather than attempt to filter or restrict the diagnostic endpoint by hand.

Timeline

Date Event
2026-08-23 CVE-2026-78174 reserved by WatchGuard (CNA), following the private report from the finder.
2026-08-27 Advisory published by WatchGuard PSIRT; fixed version 2.3.1 released.
2026-08-27 CVE record published (CVSS v4.0 9.3, Critical); mirrored to EUVD and downstream trackers.

The disclosure landed alongside a broader batch of WatchGuard advisories the same week, including pre-authentication remote code execution issues in Fireware's VPN path and several other authenticated Dimension bugs, so teams triaging this one should not view it in isolation.

A note on the discovery methodology

This is the kind of finding that comes from watching what an application actually does rather than from fuzzing it. The researcher, credited as Simone Paganessi, evidently exercised the product as a low-privileged administrator and inspected what that role could reach, including the contents of the diagnostic log, then recognized that a value in that log was a replayable credential belonging to a higher-privileged account. It is source-and-behavior review more than exploitation: no crash, no memory primitive, just the observation that a secret was in a place the wrong role could read.

The meta-lesson for the AppSec community is that the most dangerous bugs are frequently the least dramatic. A grep across a running system's logs for anything that looks like a token, a key, or an authorization header, cross-referenced against who can read each of those sinks, would surface this entire class. It does not require deep reverse engineering. It requires treating logs as a data store with an access-control policy, and asking, for every secret the application holds, "where else does this value end up, and who can read that place."


What we should learn from CVE-2026-78174

  1. A secret is only as protected as the most permissive place it is written. Encrypting a session store means nothing if the same token is copied verbatim into a log with looser access. Track every sink a credential flows to, not just its primary home, and set protection to match the secret, not the sink's original purpose.
  2. Logs are a data store, and "who can read this log" is an access-control decision. Diagnostic and debug logs routinely accumulate the most sensitive runtime data in a system. Gate them like you gate the database, and remember that exported or ticket-attached copies inherit none of the original controls.
  3. Redact credentials at the logging boundary, not by policy. Relying on developers to remember never to log a token fails eventually. Mask, hash, or truncate session identifiers, keys, and authorization headers in the logging layer itself, so the raw value cannot reach a sink even when someone logs the whole request object.
  4. Two safe decisions can compose into an unsafe one. "Log session context for support" and "let administrators read diagnostics" are each reasonable. The bug lives in their intersection. Reviews that judge functions one at a time miss vulnerabilities that only exist in the relationship between them.
  5. Privilege boundaries have to be checked against data flow, not just against endpoints. It is not enough to confirm that account-management routes require Super Administrator. You must also confirm that a Super Administrator's credentials never become readable through a route a lower role can reach. Escalation often comes through a data leak, not a missing permission check.

How Pragma Core addresses this class of problem

Pragma Core is built for exactly this kind of issue: the vulnerability that no single line looks guilty of, because it is a property of how a value flows from one place to another and who can read each of those places. Off-the-shelf scanners flag injection sinks and known-bad functions; they rarely reason about "this logged value is a live credential and this log is readable by a lower role." That reasoning is where Pragma Core is designed to operate. Every subsection below ties back to the concrete shape of CVE-2026-78174.

SAST tuned for the sensitive-data-to-log-sink pattern, not just injection

Classic static analysis chases taint from user input to a SQL or shell sink. CVE-2026-78174 has neither. The dangerous flow runs the other way: a trusted internal value (the session identifier and CSRF token) reaches a logging sink unredacted. Pragma Core's static analysis can be tuned to treat session tokens, keys, and authorization headers as sensitive sources and any logging call as a sink to watch, so a line that writes session.getId() into a diagnostic log becomes a high-confidence finding rather than something no rule was looking for.

Interactive call graphs with a vulnerability overlay

The bug is invisible if you read either half alone. The logging call looks like troubleshooting; the diagnostic endpoint's role check looks correct. Pragma Core auto-generates call graphs for a connected repository and overlays findings on them, so a reviewer can see that the value flowing into the diagnostic log is the same value that authenticates the highest-privileged session, and that the endpoint exposing that log is reachable by the lower role. The flaw was in the relationship between two functions; a graph that shows the relationship is how you catch it.

Autonomous AI agents for attack-chain investigation

Pragma Core's agents reason over chains rather than stopping at a flagged line. Pointed at a codebase like Dimension's, the relevant question is precisely the one that unravels this CVE: which values written to logs are also accepted as authentication, and which roles can read each of those logs. An agent that asks "where does this session token flow, and is any sink that receives it reachable by a principal below its owner" would have surfaced the escalation before a researcher did.

SAST and policy checks for privilege-boundary consistency

The heart of the finding is a mismatch: a Super Administrator secret readable through a Dimension Administrator route. Pragma Core can encode the privilege model as a property to enforce, checking that data belonging to a higher tier never becomes reachable through an endpoint gated to a lower tier. That turns "we require Super Administrator on account management" from a per-endpoint assertion into a whole-system invariant about where higher-tier data is allowed to surface.

Human-guided AppSec investigations

What the finder did here, operate the product as a low-privileged user, look at what that role can read, and recognize a replayable credential in a diagnostic log, is exactly the kind of targeted investigation the Pragma Core research module runs systematically. Backed by the platform's call graphs and static analysis already loaded in the workspace, an operator can drive that same "what can the junior role actually reach" question across an entire application instead of hoping one reviewer thinks to try it.


Closing thoughts

CVE-2026-78174 is not, fundamentally, a bug about WatchGuard Dimension, and it is not really a bug about logging. It is a bug about the confidentiality of a secret being silently redefined by the weakest place that secret is written, and about a privilege boundary that was enforced on endpoints but not on data flow. The same pattern lives in any architecture that has bearer credentials and verbose logging, which is to say nearly all of them: the request-logging middleware that captures headers, the debug endpoint that dumps session state, the crash handler that serializes the whole context object, the log pipeline that ships everything to a store a broader group can search.

The difference between reading this as a curiosity about one appliance and using it as a trigger to audit your own systems comes down to AppSec maturity and code visibility. Teams that treat "where do our secrets flow and who can read each destination" as a question they can answer on demand find this class of issue before a researcher does. Teams that cannot answer it wait for the advisory. Organizations that want to move from "we scan and report" to "we systematically investigate what is fragile" can reach Pragma Core at pragma-core.com for a demo.


Sources

Related posts
CVE-2026-85978: how one path normalization mismatch turned Akana's admin console into unauthenticated remote code execution
Sep 9, 2026
Qwen 3.8 27B and the year the open weights caught up: how a 17GB download started beating the frontier
Aug 19, 2026
CVE-2026-65321: how one backslash in PyAthena's quote escaper turned parameterized DELETE queries into SQL injection
Aug 3, 2026

Start securing your codebase today

Connect your repositories and let AI agents handle continuous scanning, research, and triage.

Have questions? Get in touch →