reactiveui/refit · error · ArgumentException

URL path {relativePath} must not contain CR or LF characters

Error message

URL path {relativePath} must not contain CR or LF characters

What it means

Thrown by VerifyUrlPathIsSane when a route template (the path string on a [Get]/[Post]/etc. attribute) contains a carriage return (\r) or line feed (\n) character. Refit rejects these as a defense against CRLF/header-injection attacks, since newline characters in a URL path can be smuggled into HTTP requests and corrupt headers or the request line. It is a hard validation: the route is never sent.

Source

Thrown at src/Refit.Reflection/RestMethodInfoInternal.cs:330

        if (string.IsNullOrEmpty(relativePath))
        {
            return;
        }

        if (urlResolution == UrlResolutionMode.RefitLegacy
            && !StringHelpers.StartsWith(relativePath, '/'))
        {
            throw new ArgumentException(
                $"URL path {relativePath} must start with '/' and be of the form '/foo/bar/baz'");
        }

        // CRLF injection protection
        if (!StringHelpers.ContainsCrOrLf(relativePath))
        {
            return;
        }

        throw new ArgumentException(
            $"URL path {relativePath} must not contain CR or LF characters");
    }

    /// <summary>Adds headers from a <see cref="HeadersAttribute"/> into the accumulated map.</summary>
    /// <param name="headersAttribute">The header attribute to process.</param>
    /// <param name="ret">The accumulated map, created as needed.</param>
    internal static void AddHeaders(HeadersAttribute headersAttribute, ref Dictionary<string, string?>? ret)
    {
        var headers = headersAttribute.Headers;
        for (var i = 0; i < headers.Length; i++)
        {
            var header = headers[i];
            if (string.IsNullOrWhiteSpace(header))
            {
                continue;
            }

            ret ??= [];

View on GitHub (pinned to b455f65ecc)

Solutions

  1. Sanitize the path before placing it on the attribute or in [Get(...)]: strip '\r' and '\n' (e.g. path.Replace("\r", "").Replace("\n", "")) or reject input containing them at the boundary.
  2. If the path comes from configuration, validate/trim it at load time and fail fast with a clear config error rather than letting it reach Refit.
  3. Prefer fixed literal route strings on attributes; never interpolate untrusted values directly into an attribute path — use method parameters with [AliasAs]/route parameters instead.

Example fix

// before
var route = userInput + "/items";
[Get(route)] Task<List<Item>> GetAsync();

// after — sanitize, or better, pass user data as a route parameter
[Get("items/{name}")] Task<List<Item>> GetAsync([AliasAs("name")] string name);
// and strip newlines from `name` before calling if it is untrusted
Defensive patterns

Strategy: validation

Validate before calling

// Before building the client / placing the route, validate the path.
static string SanitizeRoute(string path)
{
    if (path.IndexOfAny(new[] { '\r', '\n' }) >= 0)
        throw new ArgumentException("Route path must not contain CR or LF.", nameof(path));
    return path;
}

Prevention

When it happens

Trigger: A Refit interface method whose HTTP method attribute path argument contains '\r' or '\n' — e.g. [Get("users\n/123")] or a path built by concatenating untrusted/user-supplied input containing newlines. The check runs at interface-analysis time (RestMethodInfo construction), so it fires the first time the client is built or the method delegate is materialized, not per call.

Common situations: Dynamically building route strings from configuration or database values that accidentally include trailing newlines; copy-pasting a path from a file/terminal that introduced a line break; templating engines that inject whitespace. Under UrlResolutionMode.Rfc3986 the leading-slash rule is relaxed, but the CRLF ban is always enforced.

Related errors


AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13). Data as JSON: /api/errors/6c3043a21e919584. Report an issue: GitHub.