Description
When user input becomes the format string for APIs such as util.format, console.log or sprintf, an attacker can insert specifiers such as %s or %d and change how later arguments are interpreted. This may hide or distort important values in security or audit logs.
Potential impact
- Attacker-controlled message structure may distort the audit trail.
- Subsequent arguments may be exposed or recorded with an unintended meaning.
- Security monitoring may fail to recognize the expected log structure.
Remediation
- Keep format strings constant and pass user input as separate values.
- If input must be combined into a format string, handle it according to that API's formatting rules. Prefer avoiding that combination.
- Use structured logging to separate message templates from user values.
Examples
These excerpts assume an existing app, an authenticated req.user and a logger that supports %s formatting. A fixed format does not replace secret redaction or handling of log content such as line breaks.
Before
javascript
const util = require("util");
app.get("/search", (req, res) => {
logger.info(util.format(req.query.message, req.user.email));
res.send("ok");
});
After
javascript
app.get("/search", (req, res) => {
logger.info("search message=%s user=%s", req.query.message, req.user.email);
res.send("ok");
});
Explanation:
- Before: User input becomes the format string and can change how the subsequent argument is interpreted.
- After: The format string is fixed, and user input is passed as a value.