{"record":{"id":"6c3043a21e919584","repo":"reactiveui/refit","slug":"url-path-relativepath-must-not-contain-cr-or-lf","errorCode":null,"errorMessage":"URL path {relativePath} must not contain CR or LF characters","messagePattern":"URL path (.+?) must not contain CR or LF characters","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Refit.Reflection/RestMethodInfoInternal.cs","lineNumber":330,"sourceCode":"        if (string.IsNullOrEmpty(relativePath))\n        {\n            return;\n        }\n\n        if (urlResolution == UrlResolutionMode.RefitLegacy\n            && !StringHelpers.StartsWith(relativePath, '/'))\n        {\n            throw new ArgumentException(\n                $\"URL path {relativePath} must start with '/' and be of the form '/foo/bar/baz'\");\n        }\n\n        // CRLF injection protection\n        if (!StringHelpers.ContainsCrOrLf(relativePath))\n        {\n            return;\n        }\n\n        throw new ArgumentException(\n            $\"URL path {relativePath} must not contain CR or LF characters\");\n    }\n\n    /// <summary>Adds headers from a <see cref=\"HeadersAttribute\"/> into the accumulated map.</summary>\n    /// <param name=\"headersAttribute\">The header attribute to process.</param>\n    /// <param name=\"ret\">The accumulated map, created as needed.</param>\n    internal static void AddHeaders(HeadersAttribute headersAttribute, ref Dictionary<string, string?>? ret)\n    {\n        var headers = headersAttribute.Headers;\n        for (var i = 0; i < headers.Length; i++)\n        {\n            var header = headers[i];\n            if (string.IsNullOrWhiteSpace(header))\n            {\n                continue;\n            }\n\n            ret ??= [];","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/reactiveui/refit/blob/b455f65ecc4c97d092317e349cb775f9cfc6bcdf/src/Refit.Reflection/RestMethodInfoInternal.cs#L312-L348","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","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.","Prefer fixed literal route strings on attributes; never interpolate untrusted values directly into an attribute path — use method parameters with [AliasAs]/route parameters instead."],"exampleFix":"// before\nvar route = userInput + \"/items\";\n[Get(route)] Task<List<Item>> GetAsync();\n\n// after — sanitize, or better, pass user data as a route parameter\n[Get(\"items/{name}\")] Task<List<Item>> GetAsync([AliasAs(\"name\")] string name);\n// and strip newlines from `name` before calling if it is untrusted","handlingStrategy":"validation","validationCode":"// Before building the client / placing the route, validate the path.\nstatic string SanitizeRoute(string path)\n{\n    if (path.IndexOfAny(new[] { '\\r', '\\n' }) >= 0)\n        throw new ArgumentException(\"Route path must not contain CR or LF.\", nameof(path));\n    return path;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never interpolate untrusted input directly into an attribute route string; pass it as a method/route parameter.","Sanitize/trim configuration-derived paths at load time and fail fast with a clear error.","Treat CRLF in any URL component as a defect, not a quirk to tolerate."],"tags":["security","validation","url","crlf-injection","reflection-builder"],"backgroundTag":null,"analyzedSha":"b455f65ecc4c97d092317e349cb775f9cfc6bcdf","analyzedAt":"2026-08-13T21:20:57.878Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}