It’s not until I bumped into the revision of a PSIRT advisory, more about that later, that I was particularly aware of the “Content Security Policy” or CSP.
This is not particularly complicated and actually, a pretty useful security mechanism to prevent Cross-Site-Scripting…
What is CSP? #
CSP is simply an HTTP response header that allows web developers to declare approved sources of content that browsers are allowed to load on that page.
The specification has evolved over time and it is supported by all modern web browsers (Chrome, Firefox, Safari, Edge). If you want to dive into the details, the latest draft is available from https://www.w3.org/TR/CSP3/
What ISE was doing before #
As illustrated by the following example, captured from a guest portal preview hosted on a ISE v3.4 node, this was already implemented in ISE for quite some time (since at least v2.4):
content-security-policy:
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' http://www.cisco.com/ data:;We can see the “img-src” directive set to ‘self’ but also to Cisco.com. That means any image displayed by the portal has to be hosted directly on the ISE node but can also be sourced from the Cisco website.
However, looking closer, we can see the “script-src” directive but it includes two values, unsafe-inline and unsafe-eval, which pretty much make the whole thing useless!
“unsafe-inline” - This allows the execution of scripts defined directly in the HTML (e.g., <script>...</script> or onclick="...").
If an attacker manages to inject a <script> tag into a guest portal field, the browser will execute it immediately. By disabling this, you force the browser to only execute scripts loaded from external, verified .js files.
“unsafe-eval” - This allows the use of functions like eval(), setTimeout(string), or new Function().
These functions take a string and execute it as JavaScript code. Attackers frequently use these to obfuscate malicious payloads.
Considering a cross-site scripting (XSS) vulnerability, the attacker can pass their payload as a string to eval(), bypassing simple filters.
What changed in ISE v3.5 #
It didn’t make a lot of noise but ISE v3.5 tightened the policy by removing these two options.
That may sound simple but the ways the portals were previously generated also need to be revisited. That includes not only the default ISE interface but also any external tools such as the ISE portal builder or any customization relying on these techniques…
That’s why, for the time being, it is still possible to disable that “strict mode” and revert back to the previous directives.

If your guest portal is no longer rendering properly following your upgrade to ISEv3.5, you know what to do…
The PSIRT connection #
So what does that have to do with PSIRT? Well, if you consider this updated advisory, it is now pointing to the generic CSCwm38652. Even for a Cisco employee, it is never obvious to know what the exact changes introduced by a specific DDT are, but I suspect this is strongly related to the hardening of the CSP in ISEv3.5.
The initial advisory is still available thanks to the Wayback Machine. It was pointing to two different DDTs that had been fixed back then…more than a year later, it looks like these fixes were not good enough.
The catch is that the change has only been implemented in 3.5. If you are still running an earlier version, your only possibility to mitigate this XSS is to upgrade. Is it going to be like that for any future Cross-Site-Scripting vulnerability disclosed in the future? Time will tell…