Listen to this Post

Introduction:
A recent social media post by security researcher Gareth Heyes has reignited concerns around the `eval()` function and its potential for exploitation in modern web attacks. The cryptic message “eval a URL again! Its back” points to a sophisticated technique where URLs themselves are parsed and executed as JavaScript code, bypassing traditional security filters. This method represents a significant evolution in code injection attacks, challenging the foundational security models of web applications that rely on strict input validation and Content Security Policies (CSP). Understanding this vector is critical for developers and security professionals tasked with defending against client-side attacks.
Learning Objectives:
- Understand the mechanics of how a URL can be interpreted and executed as JavaScript code.
- Learn to identify and audit code for patterns that could enable this novel
eval()-like behavior. - Implement robust defensive coding practices and security policies to mitigate this class of attack.
You Should Know:
1. The Anatomy of a Malicious JavaScript URL
The core of this technique lies in using JavaScript’s ability to parse and execute code from string-based URLs via specific protocols.
// Example of a dangerous pattern
const url = new URL(searchParams.get('redirect_uri'));
location.href = url; // Potentially dangerous if URL is controlled by an attacker
// Malicious payload in a URL
javascript:eval('alert%28document.domain%29');//x
javascript:eval(atob('YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=='));
Step-by-step guide:
This attack exploits the `javascript:` protocol handler. When a browser navigates to a URL starting with javascript:, the subsequent code is executed in the context of the current page. The `eval()` function then dynamically evaluates the string passed to it as JavaScript code. An attacker can craft a link that, when followed by a user or processed by vulnerable application code, executes arbitrary commands. This can lead to session hijacking, data theft, or defacement.
2. Bypassing Basic Input Sanitization with Encoding
Attackers rarely send payloads in plaintext. Encoding is the first line of evasion.
// Common encoding techniques for obfuscation
// 1. URL Encoding
javascript:eval('al%65rt%28%2FXSS%2F%29');
// 2. Unicode Escape Sequences
javascript:eval('\u0061\u006c\u0065\u0072\u0074\u0028\u0027\u0058\u0053\u0053\u0027\u0029');
// 3. Base64 Encoding (often used with atob())
javascript:eval(atob('YWxlcnQoJ1hTUycp'));
Step-by-step guide:
Input filters that blacklist the word “javascript” or “eval” can be trivially bypassed. URL encoding replaces sensitive characters with `%` followed by hexadecimal codes. Unicode escapes represent characters as \uXXXX. The `atob()` function decodes a Base64 string, which can then be passed to eval(). A robust defense must decode and normalize input multiple times before inspection, or better yet, use a strict allow-list of acceptable values.
3. Exploiting Dynamic Property Accessors
Modern JavaScript features like computed property names can be used to obfuscate calls to eval.
// Using bracket notation to hide 'eval'
window<a href="'alert(1)'">'e'+'v'+'a'+'l'</a>;
// Using the Function constructor as an alternative to eval
(new Function('alert(1)'))();
// Using setTimeout/ setInterval with a string argument
setTimeout('alert(1)', 100);
Step-by-step guide:
The `eval` function can be accessed as a property of the global `window` object. By building the string “eval” dynamically, an attacker can bypass simple static analysis. The `Function` constructor is a less-direct but equally powerful function that compiles and runs code from a string. Similarly, `setTimeout` and `setInterval` can execute code from a string argument, acting as indirect `eval` mechanisms. Security tools must monitor for these patterns, not just the literal eval.
4. Hardening Content Security Policy (CSP)
A properly configured CSP is the most effective defense against these attacks.
// A strong CSP header sent by the server Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; object-src 'none'; base-uri 'self'; // A more secure, restrictive CSP Content-Security-Policy: default-src 'none'; script-src 'self' https://trusted.cdn.com; style-src 'self'; img-src 'self'; connect-src 'self'; base-uri 'self'; form-action 'self';
Step-by-step guide:
CSP is an HTTP header that tells the browser which resources are allowed to load. To block eval-based attacks, you must avoid `’unsafe-eval’` in your `script-src` directive. The second, more restrictive policy example prevents all inline scripts and eval(), forcing all code to come from specific, trusted origins ('self' and `https://trusted.cdn.com`). This effectively neutralizes the ability to execute malicious code injected via a `javascript:` URL or any other string-based code injection.
5. Server-Side and Client-Side Input Validation
Validation must be context-aware and applied consistently.
// Node.js/Express example using a validator library
const validator = require('validator');
app.get('/redirect', (req, res) => {
let url = req.query.redirectUrl;
// BAD: Simple check for a prefix
// if (url.startsWith('https://')) { ... }
// GOOD: Strict validation using an allow-list and validator
if (validator.isURL(url, { protocols: ['https'], require_protocol: true, host_whitelist: ['mydomain.com'] })) {
return res.redirect(url);
} else {
return res.status(400).send('Invalid URL');
}
});
// Client-side example (note: client-side validation is easily bypassed and must be paired with server-side checks)
function sanitizeURL(input) {
try {
const url = new URL(input);
if (url.protocol !== 'https:' || url.hostname !== 'trusted-site.com') {
return '/default-page';
}
return url.toString();
} catch {
return '/default-page';
}
}
Step-by-step guide:
Never trust client-side input. The server-side example uses the `validator` library to enforce that the URL uses HTTPS and originates from a whitelisted host. This prevents a malicious `javascript:` URL from being accepted. The client-side function uses the `URL` constructor to parse the input and then checks its protocol and hostname against a strict allow-list. Remember, client-side checks are for user experience only; they offer no real security.
- Auditing Code with Static Analysis Security Testing (SAST)
Use automated tools to find dangerous code patterns.
Using grep to find potential vulnerabilities in a codebase
grep -r "eval(" ./src/
grep -r "location.href.=" ./src/
grep -r "innerHTML.=" ./src/
grep -r "setTimeout.'" ./src/
Using a dedicated SAST tool (conceptual)
semgrep --config=p/javascript.security /path/to/code
npm audit
Step-by-step guide:
Regular code audits are essential. Simple command-line tools like `grep` can help you quickly find obvious dangerous patterns like direct calls to `eval()` or assignments to innerHTML. However, for comprehensive coverage, integrate a dedicated SAST tool like Semgrep, SonarQube, or CodeQL into your CI/CD pipeline. These tools understand code semantics and can find complex, obfuscated vulnerabilities that simple text searches would miss.
7. Leveraging the Trusted Types API
A modern browser API designed to prevent DOM-based XSS, including attacks involving `eval` of strings.
// Enforcing Trusted Types at the CSP level
Content-Security-Policy: require-trusted-types-for 'script';
// Creating a Trusted Types policy
if (window.trustedTypes && trustedTypes.createPolicy) {
const escapePolicy = trustedTypes.createPolicy('defaultPolicy', {
createHTML: (string) => {
// Sanitize the string to remove dangerous HTML
return string.replace(/</g, '<').replace(/>/g, '>');
},
createScriptURL: (string) => {
// Block javascript: URLs entirely
if (string.toLowerCase().startsWith('javascript:')) {
throw new Error('JavaScript URLs are not allowed.');
}
return string;
}
});
}
Step-by-step guide:
Trusted Types is a web platform API that forces you to process data through a policy before it can be used in dangerous sink functions like `innerHTML` or when setting `script` URLs. The CSP header `require-trusted-types-for ‘script’` tells the browser to enforce this. The code then creates a policy that defines how to sanitize HTML and explicitly blocks `javascript:` URLs. This moves the security burden from the developer remembering to sanitize every time to the browser enforcing it automatically.
What Undercode Say:
- The Abstraction War is Escalating: This technique is not a new vulnerability but a new manifestation of the old problem of mixing code and data. The battlefield has simply moved from the server-side script to the client-side URL parser.
- Defense Requires a Positive Security Model: Relying on blacklists and detecting the word “eval” is a losing strategy. The only sustainable defense is a positive security model, enforced by mechanisms like strict CSP and Trusted Types, that defines what is allowed and rejects everything else by default.
The re-emergence of eval-based URL attacks demonstrates the attacker community’s deep understanding of JavaScript’s dynamic parsing engines. They are not just exploiting implementation bugs but are leveraging the fundamental, intended features of the language and the browser in unintended ways. This signifies a maturity in web attack methodologies, moving from brute-force script injection to subtle interpreter manipulation. For defenders, this means that secure coding is no longer just about avoiding bugs; it’s about architecting applications in a way that minimizes the attack surface of these powerful native features. The focus must shift from “how to filter bad input” to “how to structurally prevent input from ever being interpreted as code.”
Prediction:
The technique of executing code via parsed URLs will rapidly evolve beyond simple `javascript:` links. We predict a rise in attacks that exploit other URL-parsing contexts within frameworks and native applications, such as deep linking in mobile apps or data URIs in desktop software. As WebAssembly (WASM) gains adoption, we may see malicious payloads delivered and instantiated via `wasm:` URLs or obfuscated within data URIs that decode to valid WASM modules. Furthermore, the integration of AI-powered code assistants could inadvertently accelerate this trend, as they might generate code patterns that dynamically execute user-provided strings without adequate safety checks, creating a new wave of AI-born vulnerabilities. The core problem of data being mistaken for executable instructions will persist, simply migrating to new runtime environments.
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Gareth Heyes – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


