What are Caja's Limitations?
This section describes various things that don't work in Caja, along with some workarounds. Some of these are deliberately not supported, some are accidentally not supported. The following material is specific to our Caja instance. Caja has a flexible configuration, so you might not see exactly the same behavior elsewhere.
Server-Side vs. Client-Side Sanitization
Caja has two similar but distinct HTML sanitization processes:
- Server-side sanitization is the full cajoler transformation applied to your application. Server-side sanitization supports complex features like scripts and stylesheets.
- Client-side sanitization happens when you set
innerHTMLin your application. Client-side sanitization is more restrictive, and will silently strip out scripts and stylesheets.
XHTML Strictness
If your application starts with an <?xml> tag or a <!DOCTYPE>
that isn't HTML, then Caja will parse your application as XML,
which is stricter than HTML, and stricter than what
browsers will usually do.
Most of the time, it's easier to tell Caja that
your app is HTML. Either omit <!DOCTYPE>, or
use some HTML doctype, such as
<!DOCTYPE html>.
However, if you do want XHTML strictness, here are some common problems you might encounter:
- Unclosed tags or unbalanced tags are fatal errors, which will prevent your application from rendering at all.
-
The
<script>elements are not special. In HTML, a<script>element will read everything as literal text until a closing</script>tag, so you don't have to do anything about "<" or "&" characters in your script. In XML, a<script>element is parsed like any other tag, and the contents must be well-formed XML. So, you will usually want to quote your script bodies with<![CDATA[...]>.
HTML Limitations
-
<a target=...> -
We allow
target=_blankandtarget=_top. Other values are deleted with a warning. Omittingtargetis the same astarget=_top. -
<embed> -
For Flash, use
<yml:swf>instead. Other embeds are not supported. -
<head> -
All contents of the
headelement are stripped. Use plain HTML starting from inside the body. -
<iframe> -
Not supported yet. Workaround depends on what you're trying to do.
-
<link rel=stylesheet> -
External stylesheets are not supported yet. Workaround is to inline the stylesheet.
-
<object> -
For Flash, use
<yml:swf>instead. Other embeds are not supported. -
<script> -
Inline scripts are supported by the server-side cajoler, but they're stripped by the client-side sanitizer. Workaround depends on what you're trying to do.
-
<script src=...> -
External scripts are not supported yet. Workaround is to inline the script.
-
<style> -
Stylesheets are supported by the server-side cajoler, but they're stripped by the client-side sanitizer. Workaround depends on what you're trying to do.
-
javascript:void(0) -
Caja currently rejects any
javascript:URLs.If you're trying to use
javascript:void(0)to make<a>buttons, try using an onclick handler instead, something like this: - URL policy
-
We currently allow
http,https, andmailtoURLs.This applies to any use of URLs, such as
<a>,<img>, etc.
CSS Limitations
[] selectors-
A subset of
[]selectors are supported, but only to the extent that the browser supports them. For example, IE7 will still ignore[]selectors. -
expression() -
Not supported. Workaround depends on what you're trying to do.
-
@import -
Not supported yet. Workaround is to inline the stylesheet.
-
:visited -
The
text-decorationproperty of:visitedis not supported. The following properties are supported:color, background-color, cursor.
JavaScript limitations
-
eval() -
Not supported. Workaround depends on what you're trying to do.
-
new Function() -
Not supported. This is similar to
eval. Workaround depends on what you're trying to do. - Assigning strings as event handlers
-
Code like this is not supported:
That's an implicit
eval, and has the same problem as expliciteval.Instead, put your event-handling code in a function, and assign the function to the event handler:
- Names ending with underscore
-
You can't use names ending with triple-underscore. Those are reserved for Caja's internal bookkeeping.
You can't use names ending with double-underscore. Those are reserved for browser extensions.
-
with (obj) { ... } -
This is not allowed since the dynamic behavior of
withmakes it difficult to analyze its security implications. The workaround is to remove thewithstatement and writeobj.fooinstead of justfoo. - Calling a method as a function
-
If
obj.foois a method that refers tothis, then peeling it off as a function and calling it directly will cause a runtime error:That doesn't really work in raw JavaScript either, but instead of silently doing the wrong thing, Caja will throw an error:
The reason is, JavaScript doesn't have bound methods, so that code probably doesn't do what you want. The code is saying to call
getElementByIdwiththisbound to the global object, which iswindow. So if it succeeded,getElementByIdwould getthis===window, instead ofthis===document.The usual way of capturing a method as a function is to wrap the method call in a function:
And that will work with or without Caja.
-
select.length -
select.lengthis not usable.
DOM Limitations
Many of the holes in the DOM interface are currently due to missing implementation, rather than security concerns. In general, if the function or property you're trying to use isn't supported, you might be able to do the same thing using interfaces that are supported.
-
document.write() -
Not supported yet.
document.writecan install malware, and it's difficult to make a safe version that duplicates the way it handles partial HTML fragments.Instead, use
innerHTML:You can also build up a DOM tree in pieces using
document.createElementand so forth. -
window.event -
window.eventisn't supported. This problem shows up if you have event-handling code like this:When you click on the text, the value you get will be
undefined.The workaround is to pass in the event as an argument. Caja always binds
eventwithinonevent=handlers, so you can rewrite the example this way:Another workaround is to use
addEventListenerinstead.

