External input used as a format string

External input used as a format string

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.

References