Skip to content

base-uri

base-uri restricts the URLs that may appear in a document’s <base> element.

It matters out of all proportion to its size. An attacker who can inject a single <base href="https://attacker.example/"> re-points every relative URL on the page, scripts included, without ever injecting a script tag.

A nonce-based script-src is exactly the policy this defeats: the nonce authorises the <script> element, and the base tag decides where that element loads from. script-src 'self' happens to catch it, because the rewritten URL is no longer same-origin - but a policy built on nonces and 'strict-dynamic' has no host check left to catch it with.

base-uri does not fall back to default-src. Leaving it out allows any base URL, whatever the rest of the policy says.

Content-Security-Policy: base-uri 'none';
Content-Security-Policy: base-uri <source-expression-list>;
  • The href of a <base> element.

base-uri has no fallback. If it is absent from the policy it restricts nothing, whatever default-src says.

Content-Security-Policy: base-uri 'self'
  • Or 'none' if you never use <base>, which is most sites. Either one closes the hijack; neither costs anything.
  • This belongs in every policy alongside object-src 'none'. Both are one line and neither has a legitimate cost - and base-uri is the one of the two that default-src cannot stand in for, which is why it is the one that gets forgotten.

Under base-uri 'self':

<base href="/app/" />

Under base-uri 'self', an injected base tag:

<base href="https://attacker.example/" />
  • Widely available across browsers since January 2020.
Field Value
violatedDirective base-uri
effectiveDirective base-uri
blockedUri https://attacker.example/
Issue title base-uri blocking attacker.example
  • Traffic on this directive deserves a look every time. A legitimate <base> is set once by your own template and reports a host you recognise; anything else on this directive is worth treating as an injection until you have proved otherwise.
  • This is a good candidate for an alert rule: the expected volume is zero.

Point your policy’s report-uri at your site’s HeaderHawk endpoint and the violations above arrive in the dashboard, grouped as described. The Quick Start sets that up in five minutes, and the integration guides cover the header syntax for each platform.