Security Headers

Sentinel automatically injects HTTP security headers into every response. The headers middleware is enabled by default when you call sentinel.Mount(), so your application gets a strong security baseline with zero configuration.

Enabled by Default

Unlike most Sentinel features, security headers are active out of the box. Every response from your application will include X-Frame-Options, X-Content-Type-Options, and Referrer-Policy headers without any configuration.

Available Headers

The HeaderConfig struct controls which security headers are injected and their values. All fields are optional — sensible defaults are applied automatically.

HeaderConfig FieldTypeDefault
Content-Security-PolicyContentSecurityPolicystring(not set)
Strict-Transport-SecurityStrictTransportSecurityboolfalse
X-Frame-OptionsXFrameOptionsstring"DENY"
X-Content-Type-OptionsXContentTypeOptionsbooltrue (emits "nosniff")
Referrer-PolicyReferrerPolicystring"strict-origin-when-cross-origin"
Permissions-PolicyPermissionsPolicystring(not set)

Configuration

Pass a HeaderConfig inside your sentinel.Config to customise the headers. Fields you omit keep their defaults.

main.gogo
1package main
2
3import (
4 sentinel "github.com/MUKE-coder/sentinel"
5 "github.com/gin-gonic/gin"
6)
7
8func main() {
9 r := gin.Default()
10
11 sentinel.Mount(r, nil, sentinel.Config{
12 Headers: sentinel.HeaderConfig{
13 ContentSecurityPolicy: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'",
14 StrictTransportSecurity: true,
15 XFrameOptions: "SAMEORIGIN",
16 XContentTypeOptions: true,
17 ReferrerPolicy: "strict-origin-when-cross-origin",
18 PermissionsPolicy: "camera=(), microphone=(), geolocation=()",
19 },
20 })
21
22 r.GET("/api/data", func(c *gin.Context) {
23 c.JSON(200, gin.H{"status": "ok"})
24 })
25
26 r.Run(":8080")
27}

To use only the defaults (X-Frame-Options, X-Content-Type-Options, and Referrer-Policy), you do not need to set the Headers field at all:

// Defaults are applied automatically — these three headers are set:
// X-Frame-Options: DENY
// X-Content-Type-Options: nosniff
// Referrer-Policy: strict-origin-when-cross-origin
sentinel.Mount(r, nil, sentinel.Config{})

Disabling Security Headers

If you need to disable the headers middleware entirely (for example, because a reverse proxy already sets them), pass Enabled as a false pointer:
disabled := false
sentinel.Mount(r, nil, sentinel.Config{
Headers: sentinel.HeaderConfig{
Enabled: &disabled,
},
})

What Each Header Does

Content-Security-Policy (CSP)

Controls which resources (scripts, styles, images, fonts, etc.) the browser is allowed to load. A well-configured CSP is one of the most effective defenses against cross-site scripting (XSS) attacks because it prevents the browser from executing injected scripts even if they make it into the HTML.

ContentSecurityPolicy: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"

CSP Not Set by Default

Sentinel does not set a default CSP because every application has different resource requirements. A restrictive policy applied blindly would break most frontends. Define a CSP that matches your application's needs.

Strict-Transport-Security (HSTS)

Tells browsers to only access your site over HTTPS for a specified duration. This prevents protocol downgrade attacks and cookie hijacking. When enabled, Sentinel sets:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

The max-age=63072000 value (2 years) with includeSubDomains and preload follows current best practices. Only enable this when your site is fully served over HTTPS.

HSTS Is Sticky

Once a browser receives an HSTS header, it will refuse to connect over HTTP for the entire max-age duration. Only set StrictTransportSecurity: true when you are certain your site and all subdomains support HTTPS.

X-Frame-Options

Prevents your pages from being embedded in <iframe>, <frame>, or <object> elements on other sites. This is the primary defense against clickjacking attacks, where an attacker overlays your UI with a transparent iframe to trick users into clicking hidden elements.

ValueBehavior
"DENY"Page cannot be framed by any site, including your own. (Default)
"SAMEORIGIN"Page can only be framed by pages on the same origin.

X-Content-Type-Options

Prevents browsers from MIME-sniffing a response away from the declared Content-Type. Without this header, a browser might interpret a text file as JavaScript or HTML, enabling attacks where an attacker uploads a file with a misleading extension. The only valid value is "nosniff", which is always set when this option is true.

Referrer-Policy

Controls how much referrer information is sent when navigating away from your site. The default "strict-origin-when-cross-origin" sends the full URL for same-origin requests but only the origin (no path or query string) for cross-origin requests, and nothing when downgrading from HTTPS to HTTP. This protects sensitive URL parameters from leaking to third parties.

ValueBehavior
"no-referrer"Never send referrer information.
"same-origin"Only send referrer for same-origin requests.
"strict-origin-when-cross-origin"Full URL for same-origin, origin only for cross-origin, nothing on downgrade. (Default)

Permissions-Policy

Controls which browser features and APIs your site can use (camera, microphone, geolocation, payment, etc.). This limits the damage if an attacker injects code into your page — even injected scripts cannot access restricted APIs.

// Disable camera, microphone, and geolocation for all origins
PermissionsPolicy: "camera=(), microphone=(), geolocation=()"
// Allow geolocation only from your own origin
PermissionsPolicy: "camera=(), microphone=(), geolocation=(self)"

Testing with curl

Use curl -v to verify that security headers are present on responses from your application.

# Inspect response headers
curl -v http://localhost:8080/api/data 2>&1 | grep -i "x-frame\|x-content\|referrer\|content-security\|strict-transport\|permissions-policy"
# Expected output (with full configuration):
# < X-Frame-Options: SAMEORIGIN
# < X-Content-Type-Options: nosniff
# < Referrer-Policy: strict-origin-when-cross-origin
# < Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
# < Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
# < Permissions-Policy: camera=(), microphone=(), geolocation=()
# With default configuration (no Headers config), you will see:
curl -v http://localhost:8080/api/data 2>&1 | grep -i "x-frame\|x-content\|referrer"
# < X-Frame-Options: DENY
# < X-Content-Type-Options: nosniff
# < Referrer-Policy: strict-origin-when-cross-origin

Check All Headers at Once

Run curl -I http://localhost:8080/api/data to see all response headers in a compact format. The -I flag sends a HEAD request and prints only the headers.

Next Steps

  • WAF -- Protect against SQL injection, XSS, and other attacks at the request level
  • Rate Limiting -- Throttle abusive traffic before it reaches your handlers
  • Configuration Reference -- Full list of all Sentinel configuration options

Built with by JB