A Content Security Policy with unsafe-inline looks harmless because the app still works, but it quietly removes the main thing CSP is there to do: stop injected scripts from running. In a mobile WebView that talks to native code through a bridge, that is not a web problem you can shrug off; an injected script can reach the device. AI builders reach for unsafe-inline because it is the path of least resistance. Here is why it is risky and what to use instead.
Short answer
No, unsafe-inline is not safe in a WebView, especially one with a native bridge. unsafe-inline lets inline scripts and event handlers run, which removes the protection a Content Security Policy gives you against cross-site scripting. In a WebView that exposes a native bridge, common in hybrid and AI-built apps, an injected script that runs because of unsafe-inline can call that bridge and reach native capabilities, turning a web flaw into device-level access. The fix is to drop unsafe-inline, use nonces or hashes for any required inline script, load only trusted content, and lock down the bridge.
What you should know
- unsafe-inline disables CSP's core defense: it allows inline scripts, so injected scripts run.
- WebView bridges raise the stakes: an XSS can call native methods exposed to the WebView.
- AI builders default to it: a permissive CSP is the easy path, so generated code often includes it.
- Nonces and hashes replace it: they let your real inline scripts run without allowing injected ones.
- Trusted content only: a bridged WebView should never load untrusted or remote content.
What does unsafe-inline actually do?
It tells the browser or WebView to trust any inline script, which is exactly what CSP is meant to prevent. A Content Security Policy without unsafe-inline blocks inline <script> blocks and inline event handlers, so even if an attacker injects markup, the script does not execute. Adding unsafe-inline to script-src removes that block, and the policy no longer distinguishes your scripts from injected ones. At that point the CSP still restricts where external scripts load from, but it has given up its strongest protection, which is stopping inline injection. For a page that reflects any user or remote content, that is the difference between a contained bug and a running exploit.
Why is it worse in a WebView with a bridge?
Because a WebView is often wired to native code, so an injected script does not stay in the web layer. Hybrid and AI-built apps expose a bridge so the web content can call native functions, on Android through an interface object and on iOS through WKWebView message handlers, and that bridge does not verify which frame or origin is calling it. So when unsafe-inline lets an injected script run, that script can call the same native methods your app uses, which OWASP describes as a path to data access and privilege escalation. The table shows the chain and where to break it.
| Setting | Risk | Safer pattern |
|---|---|---|
| script-src with unsafe-inline | Injected inline scripts execute | Use nonces or hashes and drop unsafe-inline |
| WebView loads remote or untrusted content | An XSS reaches the bridge | Load only trusted, bundled content; allow-list origins |
| Bridge exposed to all frames | Any frame can call native methods | Restrict by origin and minimize the exposed surface |
| postMessage target set to a wildcard | Messages accepted from any origin | Specify the exact expected origin, never a wildcard |
| JavaScript enabled when it is not needed | Larger attack surface | Disable JavaScript in WebViews that do not need it |
How do you fix it?
Remove unsafe-inline and replace it with a precise policy. For the inline scripts you genuinely need, add a nonce or a hash to the CSP and to the script tag, so your scripts run while injected ones do not. Load only content you control, ideally bundled with the app rather than fetched from a remote origin, and block file URLs and untrusted origins. On the bridge, expose the smallest possible set of native methods, check the origin of messages, and never set a postMessage target to a wildcard. If a WebView does not need JavaScript at all, disable it, which OWASP recommends as the simplest reduction of attack surface. A tightened CSP looks like this:
Content-Security-Policy: script-src 'self' 'nonce-Rand0mPerRequest'; object-src 'none'; base-uri 'self'
Why do AI-built apps default to unsafe-inline?
Because it makes the code work on the first try. When a builder generates a WebView screen or a hybrid page, inline scripts and styles are the quickest way to get something rendering, and adding unsafe-inline silences the CSP error that would otherwise block them. The model is optimizing for a working result, not a hardened one, so the permissive policy ships unless you change it. The same is true when there is no CSP at all, which is effectively the same exposure. Treat a generated CSP as a starting point to tighten, not a setting to accept.
What to watch out for
The first trap is thinking a WebView that only loads your own content is safe with unsafe-inline; any reflection of a URL parameter, a deep link, or remote data is an injection path, so defense in depth still matters. The second is leaving the bridge broad while you focus on the CSP, since the bridge is what makes an XSS dangerous in the first place. A pre-submission scan such as PTKD.com (https://ptkd.com) reads the compiled APK, AAB, or IPA against OWASP MASVS and reports WebView and bridge configuration, including a permissive CSP and an exposed native interface, so you can find these before submitting. The limit is that a scan flags the configuration; you still write the tighter policy and lock the bridge.
What to take away
- unsafe-inline removes CSP's protection against injected scripts, so it is not safe in a WebView.
- A native bridge turns a web XSS into device-level access, which is why unsafe-inline is worse in mobile WebViews than on a plain website.
- Drop unsafe-inline, use nonces or hashes for real inline scripts, load only trusted content, and lock the bridge to a minimal, origin-checked surface.
- Scan the build with a pre-submission scan such as PTKD.com to catch a permissive CSP or an exposed WebView bridge before you ship.

