The Catalyst SD-WAN Manager's authentication did not break. It worked. What broke was the list deciding which requests have to go through it. The list said /j_security_check; the request said /%6a_security_check, the same path with the j written in hex. To the list, two different strings. To the server behind it, the same resource. An administrator fits in that one-character gap.
We run multi-site SD-WAN and our own network with BGP and WireGuard tunnels, so an advisory about an orchestrator lands close to home and we read it yesterday out of professional obligation. But this post is not about Cisco, and it is just as useful if you own none of their kit. It is about a way of breaking that belongs to no product: it exists anywhere the layer deciding whether authentication is required and the layer resolving the resource read the same request differently. We have rules written that way too.
What was published yesterday, and the order it happened in
Advisory cisco-sa-sdwan-webauth-xr8beuuU went out on 30 September 2026 at 13:00 GMT. CVE-2026-76504, CVSS base 9.8, vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. In plain words: over the network, low complexity, no prior credentials, nobody has to click anything, and high impact on all three legs. The classification is CWE-177, improper handling of URL encoding.
The order of events matters more than the score. Cisco writes that its PSIRT became aware of active exploitation in September 2026. That is: exploited first, published second. And CISA added it to its known-exploited catalogue on that same 30 September, with a remediation due date of 3 October. Three days. And that deadline does not come from the CVSS score: it comes from the decision tree in directive BOD 26-04, which crosses four variables — whether the asset is publicly exposed, whether the CVE is in the catalogue, whether exploitation is automatable, and whether it grants total or partial control. This case ticks all four bad boxes, and that combination is the only one that carries three days and forensic triage, not just three days.
| Manager release train | First fixed release |
|---|---|
| Earlier than 20.9 | No patch: migrate to a fixed release |
| 20.9 | 20.9.10.1 |
| 20.12 | 20.12.8.2 |
| 20.15 | 20.15.6.1 |
| 20.18 | 20.18.4.1 |
| 26.1 | 26.1.2.1 |
| 26.2 | 26.2.1 |
Two details in that table worth not skimming. First: the flaw affects the product regardless of system configuration, so there is no "we do not use that part". Second: Cisco states, in as many words, that there are no workarounds that address it. The only thing on the table is your branch's patch — and mind the left-hand column, because the branch outranks recency: being on the latest 20.12 published before yesterday does not put you on safe ground unless that latest one is 20.12.8.2.
Where j_security_check comes from, and why that path had to be exempt
That odd name was not Cisco's invention. j_security_check is the action the Jakarta Servlet specification — the old Java EE — has reserved for more than twenty years for the login form: the form must POST to a URL ending in /j_security_check, with fields named j_username and j_password, and it is the container — not the application — that picks it up and decides. Any Java application with form-based authentication has that path. It is not a service door or a leftover from debugging: it is the front door, and it sits exactly where the standard says.
That path has to be exempt from the session check. It is where the session is obtained: if you demanded a valid session to reach the login form, nobody could ever log in. The exception is not surplus, not sloppiness, not technical debt. It is mandatory. Every system with authentication has at least one path evaluated without authenticating, and that path is, by construction, the most exposed one it owns.
The flaw, then, is not in having the exception. It is one step below: in how you check whether a given request falls inside it. And there, strings were compared.
Two readings of the same request
%6a is the lowercase j written as its hex code, and that is perfectly legal in a URL: the standard lets you write any character that way, and browsers and servers have been undoing it for decades without anyone noticing. So /%6a_security_check and /j_security_check are the same path written two ways. The difference is who looks at it, and when they undo it.
The front layer compares the string that arrived against its list of paths, finds no match, and so the request does not get the treatment it was due. The layer behind undoes the percent encoding and serves the same old resource. Neither does anything illegal on its own; what is missing is an agreement between them about when the encoding gets undone. MITRE's advice for CWE-177 fits on one line and is exactly the one broken here: decode and canonicalise to your internal representation before validating, and do not decode the same input twice.
Put that way it sounds like a problem for people who write products. It is not. The pattern is protecting a path by its name from a layer other than the one resolving it, and that sentence describes a lot of ordinary infrastructure: the nginx location demanding auth_basic on /admin, a WAF rule written as a regular expression over the path, a load balancer you told to "publish only /api", a framework filter chain protecting by prefix. Each of those pieces normalises, and does it well and documented. The gap does not appear inside a piece: it appears between two, when their normalisations are not identical and nobody has ever checked, because with the path written in the clear both give the same answer.
The thirty-second test, on your own stack
Take a path your proxy protects and request it twice: once as it is, once with the first letter in hex. %61 is the letter "a".
curl -s -o /dev/null -w '%{http_code}\n' https://tu.dominio/admin/
curl -s -o /dev/null -w '%{http_code}\n' https://tu.dominio/%61dmin/
Variants worth trying on the second pass: the path in capitals, with and without a trailing slash, double-encoded (%2561dmin, the percent sign itself written in hex), with a semicolon in the middle. And now the part that makes the test useful: what you are looking for is not a 200. A 200 may simply mean that resource was public and nothing was wrong. What you are looking for is a difference of judgement between the two layers, and the status code does not tell you that: the two logs side by side do. If the proxy recorded that it did not apply the rule and the application recorded that it served /admin/, you have your answer and there is no need to go further.
We will give away the likeliest result, because it is the one that confuses people: against a bare nginx you will see no difference at all, and that is a good sign — it undoes the percent encoding before deciding which location applies, so both requests are the same one to it. The gap shows up when there are two pieces and the second one touches the path again. Which is why the test worth running is not against your proxy on its own, but against the whole chain as it is actually assembled in production. And the obvious, said out loud because it costs nothing: you do this against your own systems, with permission, and you warn whoever is watching the dashboards. Fired at somebody else it is not a test, it is a different thing with a different name.
The two greps the patch does not replace
If it was being exploited before the advisory, patching closes the door but does not answer the question that matters, which is whether anyone walked through while it was open. Here Cisco did something it does not always do and that deserves credit: it published where to look, with the full path and with real sample lines. In /var/log/nms/containers/service-proxy/serviceproxy-access.log, requests to j_security_check from unknown or unauthorised IP addresses; the line the advisory publishes starts like this: [2026-09-29T23:11:13.948-05:00] "POST /%6a_security_check HTTP/1.1" 200 - 48 0 4. And in /var/log/nms/vmanage-server.log, the other side of the same request, with the username in plain view: Request Stored in Map is (/%6a_security_check) for user (viptela-reserved-..).
grep -F '_security_check' /var/log/nms/containers/service-proxy/serviceproxy-access.log | grep -F '%' grep -F 'viptela-reserved-' /var/log/nms/vmanage-server.log
The first deliberately does not look for %6a specifically: any percent sign on a _security_check line deserves a look, because the legitimate form encodes nothing in that path. Said precisely, because it matters: the grep works on lines, not on paths, so it will also pull in percent signs coming from the user agent or the query string. Those are false positives and you discard them at a glance, but it is worth knowing before you start counting. And the second file's name tells part of the story on its own: it is called vmanage-server.log because the product used to be called vManage. The commercial name changed; the file name did not, which is why the grep has to spell out the old one.
The two operational questions behind those two commands are not security questions, they are operations questions, and they usually get worse answers. First: do those files ever leave the box? If they only live on the disk of the machine you are investigating, you are investigating it using its own notes, and the action CISA requires for this CVE does not just say "patch": it points to its BOD 26-04 directive and its forensic triage requirements. It is hard to triage a log the suspect could have edited. Second: how far back do you have them? If rotation takes thirty days, the September window the advisory describes may no longer exist. We wrote about exactly this when it was the Firewall Management Center's turn: patching closes the door, but it does not erase what somebody already took.
There was no workaround, but there was a difference
Both things are true at once and it is worth not mixing them. There is no workaround for the flaw: nothing you change in the Manager's configuration fixes it. But the recommendation Cisco repeats for on-premises deployments is the usual one — prevent access from unsecured networks and restrict it with filtering to known, trusted hosts — and that one does decide how many people could have tried. A 9.8 unauthenticated over the network is devastating when the port sits where anyone can reach it, and it is a maintenance task when the orchestrator's 443 is only reachable from a management network with filtered sources.
Do not read that backwards: it does not replace the patch, and CISA's deadline is three days, and three days means three days. What changes is whether this week was an incident or a maintenance window. We already wrote about why your SD-WAN orchestrator is the key to every one of your sites, and about how responsibility splits when a network vendor ships a flaw: the vulnerability is theirs, the firewall exception is yours. This case is the same sentence with a different product; if you read it there, this paragraph is surplus to you.
The limits of what we have just said
We have not seen the exploit and have not reproduced it, and we have no affected Manager to tell you about: the mechanics we have described are the ones Cisco's advisory publishes and CISA's entry records, and that is as far as we go. The two grep commands come from the indicator description in that advisory, but the exact line format depends on your version, so look at a real line before trusting the count. The %61 test is illustrative and is not a scanner: a difference between the two layers is not automatically a hole, it is a place to look. And the fixed releases are the ones listed in the advisory of 30 September 2026: Cisco revises its advisories, and what governs is the document, not this post.
Conflict of interest, stated up front: we are not resellers of Cisco or of any SD-WAN platform, but operating other people's orchestrators, deciding where they can be reached from and applying patches against a deadline is work we bill for.
Sources (verified on 1 October 2026): the advisory identifier, its publication date and time (30-09-2026, 13:00 GMT), the CVSS base 9.8 with its vector, the CWE-177 classification, the statement that it affects the product regardless of configuration, the table of branches and first fixed releases, the declaration that no workaround exists, the recommendation to restrict access to known hosts, the note that the PSIRT became aware of active exploitation in September 2026 and the indicators of compromise naming serviceproxy-access.log and vmanage-server.log — Cisco security advisory cisco-sa-sdwan-webauth-xr8beuuU; the catalogue listing date (30-09-2026), the 3 October 2026 remediation deadline and the required action referencing BOD 26-04 and the forensic triage requirements — CISA Known Exploited Vulnerabilities Catalog; the definition of CWE-177 and the advice to decode and canonicalise before validating — CWE-177, MITRE; that j_security_check, j_username and j_password are the names the specification reserves for form-based authentication — Jakarta EE documentation; the encoded-character detail in the path and the reading of the indicators — Rapid7 analysis. The reading that "protecting by path name from another layer" is the underlying problem, the two grep commands and the %61 test are ours, not any of those sources'.
How many places can reach your orchestrator?
If the answer is "it is in the DMZ" rather than a list of sources, that fact is decided today by a vendor advisory and not by you. We design and operate multi-site SD-WAN and the security perimeter around it, including the boredom of keeping the list of who reaches the management plane and of getting the logs off the box before you need them. If you like, we will look at it on your network and tell you what is published that should not be.
Talk to everyWAN