conductor-oss/conductor · critical · IllegalArgumentException

plannerContext header '${name}' contains CR/LF — rejected to

Error message

plannerContext header '${name}' contains CR/LF — rejected to prevent HTTP response splitting

What it means

Thrown as a security guard when a plannerContext header value contains a carriage return (\r) or newline (\n) character. These characters enable HTTP response splitting attacks where an attacker injects additional headers or body content into an HTTP response. The compiler rejects them up-front before the headers are forwarded to the runtime HTTP fetch task.

Source

Thrown at agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/compiler/MultiAgentCompiler.java:3222

                String fetchRef = prefix + "_ctx_fetch_" + i;
                WorkflowTask fetch = new WorkflowTask();
                fetch.setName(PlannerContextFetchTask.TASK_TYPE);
                fetch.setType(PlannerContextFetchTask.TASK_TYPE);
                fetch.setTaskReferenceName(fetchRef);

                Map<String, Object> headers = new LinkedHashMap<>();
                Object hdrObj = e.get("headers");
                if (hdrObj instanceof Map<?, ?> hdrMap) {
                    for (Map.Entry<?, ?> h : hdrMap.entrySet()) {
                        // /dg #2: escape ONLY ``${CRED_NAME}`` patterns where
                        // ``CRED_NAME`` is an identifier — preserves literal
                        // ``${...}`` substrings that don't look like
                        // credentials. Also reject CR/LF up-front to close
                        // the response-splitting injection vector.
                        String name = String.valueOf(h.getKey());
                        String value = String.valueOf(h.getValue());
                        if (value.indexOf('\r') >= 0 || value.indexOf('\n') >= 0) {
                            throw new IllegalArgumentException(
                                    "plannerContext header '"
                                            + name
                                            + "' contains CR/LF — rejected to prevent HTTP response splitting");
                        }
                        headers.put(
                                name,
                                CREDENTIAL_PLACEHOLDER
                                        .matcher(value)
                                        .replaceAll("\\${workflow.secrets.$1}"));
                    }
                }

                boolean required = !Boolean.FALSE.equals(e.get("required"));
                int maxBytes = 16384;
                if (e.get("maxBytes") instanceof Number n) {
                    maxBytes = n.intValue();
                }
                int ttlSeconds = 60;

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Strip or reject CR/LF characters from all plannerContext header values before submitting the agent config.
  2. If the header value legitimately needs newlines (e.g., a multi-line token), URL-encode or base64-encode it first.
  3. Audit credential values for accidental trailing newlines.
  4. Sanitize any user-supplied input that flows into header values.

Example fix

// before: header value contains a newline (e.g. from credential with trailing \n)
plannerContext = [{"url": "https://wiki/api", "headers": {"Authorization": "Bearer token\nX-Injected: evil"}}]
// after: CR/LF stripped
String safeValue = rawHeaderValue.replaceAll("[\\r\\n]", "");
plannerContext = [{"url": "https://wiki/api", "headers": {"Authorization": safeValue}}]
Defensive patterns

Strategy: validation

Validate before calling

void validatePlannerContextHeaders(AgentConfig config) {
    if (config.getPlannerContext() == null) return;
    for (Map<String, Object> entry : config.getPlannerContext()) {
        Object hdrObj = entry.get("headers");
        if (hdrObj instanceof Map<?, ?> hdrMap) {
            for (Map.Entry<?, ?> h : hdrMap.entrySet()) {
                String value = String.valueOf(h.getValue());
                if (value.indexOf('\r') >= 0 || value.indexOf('\n') >= 0) {
                    throw new IllegalArgumentException(
                        "plannerContext header '" + h.getKey()
                        + "' contains CR/LF — rejected to prevent HTTP response splitting");
                }
            }
        }
    }
}

Try / catch

try {
    compiler.compile(agentConfig);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("response splitting")) {
        // strip CR/LF from the offending header value
    }
    throw e;
}

Prevention

When it happens

Trigger: An AgentConfig with plannerContext entries where at least one entry has a 'headers' map whose value (converted to String via String.valueOf) contains \r or \n. This could come from user-supplied input, a credential value that accidentally contains a newline, or a header value crafted from multi-line template strings.

Common situations: A credential placeholder value that resolves to a multi-line string (e.g., a PEM key pasted with newlines), a header value sourced from user input that wasn't sanitized, or a copy-paste from a config file that included trailing newlines. Attackers could exploit this to inject Set-Cookie or other headers.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/c83beb6c97da527c. Report an issue: GitHub.