Agent Wranglers

OPS-76Recommended

Escape line breaks in every logged value

Write each outside value into its own log field, through an encoder that escapes carriage returns, line feeds and other control characters. Never paste input into the message text.

How to do it

A user name that holds a line break can add a forged line to the log, such as a fake admin sign-in. That misleads whoever reads the log after an attack, and the weakness is listed as CWE-117. A JSON logger escapes control characters inside fields, which is one more reason for Log structured events. A plain text format needs the value escaped before it is written. A log viewer that shows HTML must escape the value as HTML too. The events worth logging for attacks are in Log attacks without personal data.

Examples

JavaScript example

import pino from 'pino';

const log = pino();
// The value goes in a field, and the JSON encoder escapes the line break.
log.warn({ event: 'signin.failed', username: 'alice\nINFO sign-in ok user=admin' });

Python example

import json
import logging

class JsonFormatter(logging.Formatter):
    def format(self, record):
        return json.dumps({"level": record.levelname, "event": record.getMessage(), **getattr(record, "fields", {})})

handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
log = logging.getLogger("shop")
log.addHandler(handler)
log.warning("signin.failed", extra={"fields": {"username": "alice\nINFO sign-in ok user=admin"}})

How to check

A unit test logs the user name alice\nINFO sign-in ok user=admin. The output holds exactly one new line for that event, and the value shows the line break as \n.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/operations/logs/log-injection">Agent Wranglers operations and observability playbook</a>. In code you write, add a comment next to it with the same link.