The problem I always see with practically all templating systems is the lack of proper escaping of input data.
For example, the function 'tag-name' really needs to HTML-escape the input parameter content.
The simple example (tag-name "div" "Hello world") breaks down when "Hello World" is replaced by a variable reference.
Fortunately this is an relatively easy problem to solve. A better definition for tag-name is something like:
The function to-html will return the HTML-escaped version of content. The function html returns an object/string that marked as already being HTML-escaped. They work together so that (to-html (html x)) just returns x.
A similar type system can be set up to handle url escaping rules.
If the templating system doesn't keep track of what is escaped and what isn't then that burden is left to the programmer with all of the associated risks of producing malformed output and creating opportunities for injection attacks.
For example, the function 'tag-name' really needs to HTML-escape the input parameter content. The simple example (tag-name "div" "Hello world") breaks down when "Hello World" is replaced by a variable reference.
Fortunately this is an relatively easy problem to solve. A better definition for tag-name is something like:
(defun tag-name (name content) (html (format nil "<~A>~A</~A>" name (to-html content) name))
The function to-html will return the HTML-escaped version of content. The function html returns an object/string that marked as already being HTML-escaped. They work together so that (to-html (html x)) just returns x.
A similar type system can be set up to handle url escaping rules.
If the templating system doesn't keep track of what is escaped and what isn't then that burden is left to the programmer with all of the associated risks of producing malformed output and creating opportunities for injection attacks.