CWE-96, Improper Neutralization of Directives in Statically Saved Code (Static Code Injection), is code injection with a delay. The product receives input and inserts it into an executable resource, such as a library, configuration file or template, without neutralizing the code syntax. The code does not run at the moment of the request. It runs later, when something loads the file.
MITRE lists PHP, Perl and interpreted languages. The pattern fits any app that writes settings, themes, caches or logs into files that its own interpreter will later read as code.
How it happens
A classic case is a settings page that saves values by rewriting a PHP file.
<?php
// Vulnerable: the posted value is written into a PHP file
$title = $_POST["site_title"];
file_put_contents("config.php", "<?php \$site_title = '" . $title . "'; ?>");
If the attacker posts a title that closes the quote and adds a statement, that statement is now part of config.php. Every request that includes the file runs it.
MITRE's observed examples show the shape across several products:
- CVE-2002-0495: Perl code injected directly into a CGI library file from parameters to another CGI program.
- CVE-2005-1876: direct PHP code injection into a supporting template file.
- CVE-2005-1894: direct code injection into a PHP script the attacker can access.
- CVE-2003-0395: PHP code from the User-Agent HTTP header inserted into a log file that is implemented as a PHP script.
That last one is worth a second look. The attacker needed no form. A request header was enough, because the log was a script.
What an attacker gains
MITRE's consequences match general code injection: reading files and application data, bypassing protection (injectable code can control authentication, which may make the flaw remote), gaining privileges, loss of integrity, confidentiality and availability including code execution, and hiding activity because injected code often goes unlogged.
How to find it
MITRE says static analysis can find some instances. Look for code that writes files and then check the file type: a write to a .php, .pl, .py, template, or config path that interpolates any variable derived from a request, header, or database field.
Also check for stored data that is later included. Cache files, generated language packs, and "export as script" features are common places.
How to fix it
MITRE gives two linked mitigations.
- Validate input with an allowlist. Assume all input is malicious, accept only known good, and check length, type, range and syntax. Do not rely only on blocking bad input.
- Encode output. Perform proper output validation and escaping to neutralize all code syntax from data written to code files.
The cleaner design is to stop storing data inside code. Keep settings in a data format such as JSON or a database row, and let code read it as data.
<?php
// Safer: store data as data, never as executable text
file_put_contents("config.json", json_encode(["site_title" => $_POST["site_title"]]));
json_encode escapes the value, and the file is never interpreted as PHP. If you must generate code, escape every value for the exact context it lands in, such as a quoted string, and keep the generated file outside any path the web server executes.
Quick check
How does static code injection differ from eval injection?
Eval injection executes input immediately. Static code injection saves input into a file that will be executed later, so the payload waits until the file is loaded.