Does a Website Need CSP If There Is No JavaScript code?

I ask because I once broke my website without ever refreshing my browser cache and I thought my CSP worked fine but then I decided to take it off because I feel like Content Security Policy is nothing more than a hindrance. Here is my website:

A few weeks ago, I moved from ClassicPress to my custom flat-file format because I wanted to get away from using a database for powering my website. All the Internet talks about is “why you should care about CSP” or “why you need CSP” without talking about whether CSP is appropriate for a personal website or not. Sure, there is documentation regarding Content Security Policy on the Internet, but I feel like this whole thing about documentation is JUST not enough. I mean, I struggle with Content Security Policy a whole lot. It’s like there is not enough documentation that covers recommendations on what CSP works best for my website.

I once used nonces (that I randomly created without knowing what I am doing) to using inline-unsafe for styles (I know: very bad practice) when I moved to flat file and got rid of JavaScript code, but it just so happens that when I set default-src to none while setting styles, media, and images to self and data:, I thought it worked fine later to find out in a later time that I broke my website using Content Security Policy.

With that in mind, if I only use assets stored in my VPS server, is it possible for anyone to cause a cross-site-scripting attack against my website?

How about my router.php? Are there any vulnerabilities to be aware of?


class Router
    function __construct()
        $root = $_SERVER['DOCUMENT_ROOT'];
        $url = "";
        $isCategory = false;
        $controller = new HomeController();
        if(isset($_GET['url']) &&
           $_GET['url'] != "index.php")
            $arrayURL = explode('/', filter_var(rtrim($_GET['url'], '/'),
            if($arrayURL[0] == "sitemap.php")
            if($arrayURL[0] == "category")
                $isCategory = true;
            $url = join('/',$arrayURL);
        else if(isset($_GET['page']))
            else call_user_func_array([$controller,"error"],
            $qstrNum = count(explode('&', $_SERVER['QUERY_STRING']));
            if($qstrNum > 1)

I do use mod_security that reports a forbidden when I try to do something like ?q=/bin/falseI even tried doing page= but I got a forbidden as well from my Apache server. Of course, I’m pretty sure there might be workarounds in order to cause havoc to my site that I’m not aware of. This is more of a server-side and not client-side which I have concerns with when it comes to using Content Security Policy.

In my experience and in my opinion, the more I harden my website for security, the more likely it’s going to break, but that’s just me.

Update: I think I found a solution:

Header set Content-Security-Policy "default-src 'unsafe-inline' data:; script-src 'none'; img-src 'self' data:; media-src 'self' data:;"

This may not be secure at all, but at least I now have the basic Content Security Policy in place. Yes, unsafe-inline is very bad, but I’d rather take the easy route instead of knowing how to set nounces properly… Content Security Policy is a pain…

I never used CPS, but I also never really hosted stuff outside of barebones Joomla and Wordpress. I made static html pages before.

I’d say if all you do is static websites, then either maintain them manually in a git, or use something like Hugo, Jekyll or shell SSG6. If your security to your website is strict around other ports, then there’s no reason to really be worried. Most hacks happen around breaking in the backend and accessing API calls to the backend. There is where the XSS is happening. Or if you aren’t using encryption, MITM.

If you really care about the security of your users and their bandwidth, you can remove all images from the website and just link them, meaning the site would look pretty much the same in an rss reader, but it makes it a bit annoying to click on all the pictures, if there are a lot. Or you can host 2 versions. But that is going a bit too far IMO. As far as local content is concerned, then you should be good. Again, most attacks happen on the backend, so protect the access to your site’s administration.

Your website easily passed my NoScript, PrivacyPossum and Decentralized extensions, good job sir!

nmap -sS
Starting Nmap 7.93 ( ) at 2023-03-19 02:06 EET
Nmap scan report for (
Host is up (0.25s latency).
Other addresses for (not scanned): 2604:a880:800:10::fe:1
Not shown: 994 closed tcp ports (reset)
25/tcp  filtered smtp
80/tcp  open     http
135/tcp filtered msrpc
139/tcp filtered netbios-ssn
443/tcp open     https
445/tcp filtered microsoft-ds

I see there is no SSH port open to the public, which is good, but that mail ports there are worrisome. Unless your domain is actually just a dumb tcp redirector, a la iptables, netcat or rinetd, I wouldn’t be hosting the email on the same server, even if it’s convenient. Or at least, I’d put them in containers, to try to prevent the host and thus your website from being exploited via mail vulnerabilities.

The only ports open are 80 and 443 in my end.

gpadmin@multiservers:/var/www/$ sudo nmap -sS
[sudo] password for gpadmin: 
Starting Nmap 7.93 ( ) at 2023-03-18 23:21 EDT
Nmap scan report for (
Host is up (0.028s latency).
Other addresses for (not scanned): 2604:a880:800:10::fe:1
Not shown: 998 filtered tcp ports (no-response)
80/tcp  open  http
443/tcp open  https

Nmap done: 1 IP address (1 host up) scanned in 5.05 seconds

Where did yours came from?

Anyway, stylesheets and images are not a problem for me. Anything I host is in my server and I do not use any third-party servers for hosting images. Also, my website does not have a web UI for administration.

For example, when I need to push my changes to my server, I can do this:

rsync -r -e 'ssh -p (whatever random port)' --progress /var/www/ (whatever user)@(whatever the domain):/var/www/grayson-mvcblog

So yeah, the backend is only in my development server VM hosted in my own server.

(Looking at your NMAP…)

Actually, look at this:

25/tcp  filtered smtp

FILTERED!!! That means I do NOT have a mail server running and my iptables firewall does not allow all ports except 80 and 443.

True, generally filtered does not mean open, however, it means that a deny response was sent. There are 3 kind of firewall rules: allow, deny and (silent) drop. Open mean allowed. Dropping packets is generally done for hidden services and if a rule drops a packet, the host trying to connect to a server will see that just as if a service was never there.

Filtered means something (either the host or a network firewall) actively rejected it, which is the deny option. A deny rule will send a response to the host that the connection has been denied. If you don’t know about these services, that means it’s your hosting provider or ISP blocking these.

All good then.

You know what? I forgot to change from :INPUT ACCEPT to :INPUT DROP once I have my firewall configured properly, but then I’m good; however, I think we are getting off-topic when it comes to talking only about website security. I was merely talking about Content Security Policy when it comes to hardening my website.

CSS can also make requests to external domains, and unlike JS you can’t disable it on the browser so CPS it’s an additional layer of defense against that. However if you are sure you control all your site’s assets and are not using any third-party dependencies, plugins, etc., then I think it’s safe to not include it.

For reference:

Given that you mention “CPS,” I take it you meant “Content Policy Security” instead of CSP for “Content Security Policy.” :slight_smile:

Anyway, thanks. I will read the article.

Actually, I visited this page and it said that the tester requires JavaScript. With NoScript blocking the domain name by default, I cannot perform the test.

This makes me wonder if there are CSS-only methods that would make it malicious without JavaScript… See, this is the whole point about whether I should have Content Security Policy (CSP, not CPS, as in “Content Policy Security”) with NO JavaScript code of any kind in my website.

I did mean CSP (Content Security Policy), I don’t even know if there’s such thing as CPS? Probably, one negative aspect of technology is the amount of acronyms thrown around everywhere, I don’t even notice these typos anymore :joy:

The tester mentioned on that website needs JavaScript to run but not the vulnerability itself:

If the vulnerability doesn’t involve JavaScript, why does the vulnerability tester require JavaScript?
While the CSS Exfil attack doesn’t require JavaScript to function, this page requires a few lines of JavaScript to check to see if the exploit succeeded in loading the images.

This is a CSS-only vulnerability.

Well then I am not too worried about that vulnerability.


1 Like