Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

CSP: javascript: links, eval and string timers

The remaining kinds of inline code a Content Security Policy blocks - javascript: links, eval(), new Function(), string timers, scripts inserted as HTML and JSONP - and how to replace each in an old extension.

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/help/extension-development/part-4-upgrading/csp-javascript-links-and-eval.md

On this page

CSP: javascript: links, eval and string timers

Part 4, chapter 15. After script blocks and event handler attributes, a few smaller kinds of inline code remain. Each is blocked by a policy without 'unsafe-inline' or 'unsafe-eval', and each is easy to replace once you know it is there.

Find them

cd extension/myoldext
grep -rnE "href\s*=\s*[\"']\s*javascript:|action\s*=\s*[\"']\s*javascript:" --include='*.tpl' design/
grep -rnE "\beval\s*\(|new\s+Function\s*\(|set(Timeout|Interval)\s*\(\s*[\"']" --include='*.js' --include='*.tpl' design/
grep -rnE "\.(html|append|prepend|after|before)\(\s*[^)]*<script|globalEval|callback=\?" --include='*.js' design/
<a href="javascript:void(0);" onclick="myOldExtToggle( 'details' );">Details</a>
<a href="javascript:history.back();">Back</a>
<a href="javascript:window.print();">Print</a>

A javascript: URL is inline code. Replace each according to what it does:

Old linkReplacement
href="javascript:void(0)" with an onclicka <button type="button"> with a data attribute, handled by your file's click listener
href="javascript:history.back()"a real link to the previous page, if you know it ({$node.parent.url_alias|ezurl}), or a button with data-<ext>-back
href="javascript:window.print()"a button with data-<ext>-print
href="javascript:document.forms.x.submit()"a real submit button in the form

A button is the right element for "do something on this page"; a link is the right element for "go somewhere". Using the right one also fixes keyboard and screen reader behavior. A <button> in a form submits the form unless it has type="button".

<button type="button" class="button" data-myoldext-toggle="details" aria-expanded="false" aria-controls="details">{'Details'|i18n( 'extension/myoldext' )}</button>
<div id="details" hidden>...</div>
document.addEventListener( 'click', function( e )
{
    var button = e.target && e.target.closest ? e.target.closest( '[data-myoldext-toggle]' ) : null;
    if ( !button )
        return;
    var panel = document.getElementById( button.getAttribute( 'data-myoldext-toggle' ) );
    if ( panel )
    {
        panel.hidden = !panel.hidden;
        button.setAttribute( 'aria-expanded', panel.hidden ? 'false' : 'true' );
    }
} );

eval() and new Function()

eval() and new Function( '...' ) run a string as code. A policy blocks them unless it contains 'unsafe-eval', which Exponential's shipped directives do not. Old code used them for two reasons:

UseReplacement
Parsing JSON: eval( '(' + text + ')' )JSON.parse( text )
Calling a function by name: eval( name + '()' )a map of functions: var actions = { save: save, reset: reset }; actions[name]();
Reading a value by path: eval( 'config.' + key )config[key]

The JSON case is also a security fix: eval() runs whatever the server sent, and JSON.parse() only reads data.

String timers

// before: a string is code, like eval()
setTimeout( "myOldExtRefresh('" + id + "')", 1000 );

// after: a function
setTimeout( function() { myOldExtRefresh( id ); }, 1000 );

setInterval() works the same way.

Scripts inserted as HTML

Old Ajax code often loaded a block of HTML with a <script> inside and inserted it, relying on jQuery to run the script:

$( '#panel' ).html( response );   // response contains <script>...</script>

Under the policy, jQuery's evaluation of that inline script is blocked. Change the server side so it returns only data (JSON) or only markup, and keep the code in your file:

jQuery.getJSON( url, function( data )
{
    var panel = document.getElementById( 'panel' );
    panel.textContent = data.message;
} );

With ezjscore, the server side is a server function and the client calls it through the kernel's JavaScript API; see Ajax with ezjscore server functions.

JSONP

JSONP (callback=? in a jQuery URL, or a <script src="...?callback=..."> built by hand) loads a script from another host. Under script-src 'self' it is blocked unless that host is allowed. Most services that offered JSONP now offer JSON with CORS; use fetch() or jQuery.getJSON() without the callback, and add the host to connect-src instead.

Allowing what really must be allowed

Some things cannot be moved into your own files, for example a map service's script. For those, add the exact host to the policy for the siteaccesses that need it, in the settings, not by loosening it for everyone. How the settings work, including additional sources per directive, is in Content Security Policy.

Become an Exponential Partner

Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x