How a subtle CSP misconfiguration broke our admin panel and how we fixed it
0 net
CSP Failure in Rails And What It Taught Us About Security Expertise Projects About Us Careers Blog Contact Us Solutions Cloud App Development Data Engineering AI/ML Development Generative AI LLM Development Services Staff Augmentation Dedicated Development Team Custom Software Development DevOps Services Technologies Python Development NodeJS Development ReactJS Development React Native Development Ruby on Rails Development Products Marketplace Development LMS Development MVP Development SaaS Development CRM Development Close 4.9 on Clutch Oleksandr Pozniak How a Subtle CSP Misconfiguration Broke Our Admin Panel and What We Did About It Tech consulting While working with a client, one of the most respected construction companies in the U.S., Syndicode was helping deliver a custom internal tool built on Ruby on Rails and ActiveAdmin. Everything was on track until a quiet failure brought key workflows to a stop. Dynamic forms stopped responding. Admins couldn’t create or update records. Support tickets started coming in. And the frontend gave no clear indication of what went wrong. The cause? A missing CSP nonce —a subtle security misconfiguration that blocked inline JavaScript without breaking the UI visually. In this post, we’ll break down how we diagnosed the issue, why it matters for security and functionality, and how we implemented a fix that restored full behavior without compromising CSP rules. Whether you’re working with Rails, ActiveAdmin, or any secure-by-default stack, this one’s worth bookmarking. A silent failure that broke key admin workflows Everything looked fine on the surface. No visual bugs, no alerts, no errors in the deployment pipeline. But users began reporting that certain admin forms, the ones they relied on daily, had stopped working. Fields no longer showed or hid dynamically Form validations didn’t trigger Buttons stayed disabled no matter what users selected And yet, the frontend didn’t throw any visible errors. The only clue was tucked away in the browser console: Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'" Because the console message only shows a simplified view of the violation, we checked the network response headers to see what was actually being enforced. Sure enough, the Content Security Policy header included: script-src 'self' No hash, no nonce, no exceptions. The browser was blocking all inline JavaScript code due to a CSP inline script violation. From there, we dug deeper to validate what scripts were being blocked and why. Inspecting the page’s HTML source confirmed that ActiveAdmin was still rendering small inline scripts using script do … end blocks, which generate a script element directly in the view, powering dynamic behavior in the forms. These script elements controlled dynamic form behavior but were being silently ignored by the browser due to CSP restrictions. Next, we looked at the Rails CSP configuration . At the time, the app was set up with a strict script-src ‘self’ policy in the application config file, but hadn’t yet integrated nonce support. This is a common state for teams tightening browser-side security: the policy is technically safe, but operationally incomplete. The result was predictable and invisible. A security layer meant to protect the app ended up disabling legitimate functionality. And because the UI didn’t visibly break, the issue slipped past automated checks. This also highlighted the need to strengthen our test coverage for web pages that depend on inline script execution, especially in environments with strict CSP settings. We’ve since added targeted checks to flag silent failures like this early, even when the UI appears visually correct. Why Content Security Policy breaks inline JavaScript Modern browsers enforce Content Security Policy (CSP) rules to prevent malicious code from executing in the browser, especially code injected via cross-site scripting (XSS). It’s a critical layer of defense, but if misconfigured, it can just as easily block legitimate behavior. In our case, the CSP directive in the response headers was: script-src 'self' That tells the user’s browser: only allow JavaScript from the site itself and block all inline scripts by default . Inline JavaScript is considered risky because it can be easily exploited if your app ever becomes vulnerable to XSS. The issue was that ActiveAdmin relied on inline scripts to drive form interactivity: small blocks rendered inline via script do … end. These aren’t dangerous in this context, because they’re generated by Rails itself. But to the browser, there’s no way to know that unless we explicitly tell it. That’s where nonces come in. A nonce is a random string generated for each request, added to both the CSP header and each inline