Sheath rule
security-no-inline-js
Inline JavaScript event handlers should not be used.
(dangerous) Preset: strict
#Why
Strict Content Security Policies block inline event handlers. Moving handlers into JavaScript also keeps executable code out of markup and avoids interpolating template data into scripts.
#Examples
#Bad
<!-- Inline event handlers -->
<button onclick="handleClick()">Click me</button>
<input onchange="validateInput(this)">
<form onsubmit="return validateForm()">
<a href="#" onmouseover="showTooltip()">Hover me</a>
<div ondrop="handleDrop(event)" ondragover="allowDrop(event)">
#Good
<!-- Use data attributes + external JS -->
<button data-action="click">Click me</button>
<!-- Alpine.js (separate directive, not inline) -->
<button x-on:click="handleClick">Click me</button>
<button @click="handleClick">Click me</button>
<!-- Livewire -->
<button wire:click="handleClick">Click me</button>
<!-- External JavaScript -->
<script src="/js/app.js"></script>
// In external JS file
document.querySelector('[data-action="click"]')
.addEventListener('click', handleClick);
#Event Handlers Detected
The supported HTML, DOM, and SVG event-handler attributes include widely deployed platform-specific handlers:
| Category | Events |
|---|---|
| Mouse | onclick, ondblclick, onmousedown, onmouseup, onmouseover, etc. |
| Keyboard | onkeydown, onkeyup, onkeypress |
| Focus | onfocus, onblur, onfocusin, onfocusout |
| Form | onchange, oninput, onsubmit, onreset, onselect |
| Window | onload, onunload, onerror, onresize, onscroll |
| Clipboard | oncopy, oncut, onpaste |
| Drag | ondrag, ondragstart, ondragend, ondrop |
| Touch | ontouchstart, ontouchmove, ontouchend |
| Pointer | onpointerdown, onpointerup, onpointermove, onpointerrawupdate |
| Media | onplay, onpause, onended, onvolumechange |
| SVG animation | onbegin, onend, onrepeat |
| Platform/CSS/WebXR | onfullscreenchange, onscrollsnapchange, onanimationend, ontransitionend, onbeforexrselect |
#Options
Use this option to permit selected event-handler attributes.
| Option | Type | Default | Description |
|---|---|---|---|
allowed |
array | [] |
Event handlers to allow (case-insensitive) |
<?php
// Allow specific handlers (not recommended)
'security-no-inline-js' => ['warning', [
'allowed' => ['onclick'],
]],
#Auto-fix (Dangerous)
The fixer removes inline handlers entirely. This is marked as dangerous because:
- It removes functionality
- The behavior must be reimplemented in external JS
- Review carefully before applying
The fix is withheld when a handler's value is dynamic (for example a Blade echo inside the attribute), since removing the attribute would delete the expression with it.
#Notes
- Alpine.js
x-on:and@clickare NOT inline handlers (they're directives) - Livewire
wire:clickis NOT an inline handler (it's a directive) - Those compile to event bindings rather than an
on*attribute, which is why they pass
#References
- OWASP: XSS Prevention Cheat Sheet - Best practices for preventing XSS attacks
- MDN: Content Security Policy - How CSP blocks inline scripts
#Related Rules
- security-no-raw-echo - Avoid XSS vulnerabilities