How we mastered Content Security Policy
Infrastructure
Monitoring
Security

How we mastered Content Security Policy

Karol Szpakowski
Karol Szpakowski

This is the story of how we navigated the complexities of CSP, the lessons we learned, and the practices we established to make it an integral part of our security posture.

At monday.com, we believe that building secure applications is a responsibility we owe to our users. We also know that ensuring security shouldn’t come at the cost of developer productivity. That’s why, when we decided to implement a Content Security Policy (CSP) to mitigate threats like cross-site scripting (XSS) and data injection attacks, we set out to make the process as seamless as possible for our teams.

What is CSP?

CSP is a security feature implemented through HTTP response headers or meta tags. It controls what resources (scripts, styles, images) are allowed to load on the page. By enforcing these rules, CSP helps prevent malicious content from being executed in the browser.

Rules are divided into groups called directives, each responsible for protecting a particular type of resource. For example:

frame-ancestors: Lists domains where a site can be embedded in an iframe, protecting against clickjacking attacks.

script-src: Controls script sources to prevent XSS attacks.

connect-src: Filters targets for XHR requests, preventing connections to malicious servers.

For a detailed description of CSP and its directives, refer to the MDN documentation.

A solution with hidden complexity

When we first explored CSP, it seemed deceptively simple: define a set of rules, add them to HTTP headers, and voilà! Instant security upgrade. But as we dug deeper, we uncovered hidden complexities:

– With dozens of services in our microservices architecture, maintaining a consistent CSP across environments felt like trying to solve a Rubik’s Cube blindfolded.

– As our list of domains grew, the CSP header became unwieldy—too long for some API clients to handle.

– Without clear observability, we couldn’t tell if our policies were working or if domains in our CSP were still needed.

At monday.com, we embrace challenges as opportunities to innovate, so we set out to create a solution that addresses these complexities while prioritizing developer experience.

Crafting a scalable CSP strategy

The turning point: Centralizing configuration

We found our breakthrough by centralizing CSP management at the API gateway level. This decision, while seemingly straightforward, revolutionized how we approached CSP. By using Ambassador API Gateway, we could:

1. Decouple CSP configuration from application code, avoiding the need for redeployments when policies change.

2. Apply policies consistently across all services.

3. Manage CSP as code using GitOps, ensuring every change is version-controlled, peer-reviewed, and auditable.

Centralizing CSP management through the API gateway ensures consistent policies across services and simplifies updates.

Empowering developers through automation

Once we had a centralized system, the next challenge was maintaining it. With every new service or feature, the CSP grew more complex. How could we be sure policies weren’t overlapping or redundant?

That’s when we decided to build a custom GitHub Action. This tool became our CSP guardian, automating checks to:

– Flag duplicate entries.

– Ensure required directives are present.

– Detect overlapping wildcard domains.

– Identify obsolete configurations.

By integrating this validation into our CI pipeline, we turned CSP management into a collaborative effort, empowering every developer to contribute without risking policy bloat or misconfiguration.

Our custom GitHub Action validates CSP configurations to ensure consistency and prevent errors.

Making CSP a team effort

One of the most rewarding parts of our CSP journey was seeing how the team rallied around it. Initially, we worried about resistance—after all, no one loves extra steps in their workflow. However, our engineers quickly saw the value CSP brought to our security posture.

We made CSP accessible to everyone while keeping the security team as code owners for final reviews. To foster adoption, we hosted interactive tech talks. In one session, we demonstrated an XSS vulnerability on a test site and showed how CSP instantly neutralized it. Seeing CSP in action made its value crystal clear.

Interactive tech talks helped the team understand CSP’s value and fostered collaboration.

How observability drives better security

As we rolled out CSP, we faced one persistent challenge: how do we know if it’s working? CSP operates on the client side, so we needed a way to collect and analyze violation reports.

This is where Sentry became indispensable. By configuring report-to in our CSP headers, we set up a feedback loop:

1. Sentry collected violation reports from users’ browsers.

2. We analyzed the data to identify and fix misconfigurations.

3. We verified obsolete domains using the report-only mode, safely removing them once no violations were detected.

Sentry provides critical insights into CSP violations, helping us refine policies and detect threats.

Scaling CSP with confidence

Rolling out CSP at scale required a careful balance between ambition and caution. We adopted a phased approach:

1. Start in Test Environments: CSP changes were first applied in staging to catch issues early.

2. Gradual Production Rollout: Updates were deployed region by region.

3. Test with Report-Only Mode: Before enforcing changes, we used report-only mode to monitor potential violations.

This methodical rollout ensured we could iterate quickly without disrupting user experiences.

A phased rollout strategy helped us implement CSP changes without disruptions.

What we learned along the way

Looking back, our CSP journey taught us a lot – not just about the tool itself, but about what it takes to build security features into a fast-paced development environment. Here are our top takeaways:

1. Start Strict: CSP is the most straightforward to implement at the beginning of a project. Starting with strict policies and relaxing them as needed simplifies long-term management.

2. Invest in Observability: Tools like Sentry are essential for understanding how CSP affects your application in the wild.

3. Automate Everything: Validation tools and CI checks reduce errors and empower teams to manage CSP collaboratively.

4. Document as You Go: Keeping a clear and easy-to-understand record of CSP directives and their meaning can really save us from potential headaches in the future!

The impact of CSP: Safer web applications

Today, CSP is more than a policy for us – it’s a mindset. It’s a way to build trust with our users, knowing we’re doing everything possible to protect their experience. By centralizing, automating, and collaborating, we’ve made CSP an integral part of our security posture without compromising agility.

If you’re considering CSP for your application, we hope our story inspires you. It’s a journey worth taking — and with the right tools and practices, it can be smoother than you think.