ghsa-5vcm-3xc3-w7x3
Vulnerability from github
Published
2021-09-22 19:18
Modified
2022-10-25 20:24
Summary
Response Splitting from unsanitized headers
Details

Impact

http4s is vulnerable to response-splitting or request-splitting attacks when untrusted user input is used to create any of the following fields:

  • Header names (Header.nameå
  • Header values (Header.value)
  • Status reason phrases (Status.reason)
  • URI paths (Uri.Path)
  • URI authority registered names (URI.RegName) (through 0.21)

The following backends render invalid carriage return, newline, or null characters in an unsafe fashion.

| | blaze-server | ember-server | blaze-client | ember-client | jetty-client | |:---------------|:-------------|:-------------|:-------------|--------------|--------------| | header names | ⚠ | ⚠ | ⚠ | ⚠ | ⚠ | | header values | ⚠ | ⚠ | ⚠ | ⚠ | | | status reasons | ⚠ | ⚠ | | | | | URI paths | | | ⚠ | ⚠ | | | URI regnames | | | ⚠ < 0.22 | ⚠ < 0.22 | |

For example, given the following service:

```scala import cats.effect. import org.http4s. import org.http4s.dsl.io._ import org.http4s.server.blaze.BlazeServerBuilder import scala.concurrent.ExecutionContext.global

object ResponseSplit extends IOApp { override def run(args: List[String]): IO[ExitCode] = BlazeServerBuilderIO .bindHttp(8080) .withHttpApp(httpApp) .resource .use(_ => IO.never)

val httpApp: HttpApp[IO] = HttpApp[IO] { req => req.params.get("author") match { case Some(author) => Ok("The real content") .map(_.putHeaders(Header("Set-Cookie", s"author=${author}"))) case None => BadRequest("No author parameter") } } } ```

A clean author parameter returns a clean response:

sh curl -i 'http://localhost:8080/?author=Ross'

```http HTTP/1.1 200 OK Content-Type: text/plain; charset=UTF-8 Set-Cookie: author=Ross Date: Mon, 20 Sep 2021 04:12:10 GMT Content-Length: 16

The real content ```

A malicious author parameter allows a user-agent to hijack the response from our server and return different content:

sh curl -i 'http://localhost:8080/?author=hax0r%0d%0aContent-Length:+13%0d%0a%0aI+hacked+you'

```http HTTP/1.1 200 OK Content-Type: text/plain; charset=UTF-8 Set-Cookie: author=hax0r Content-Length: 13

I hacked you ```

Patches

Versions 0.21.29, 0.22.5, 0.23.4, and 1.0.0-M27 perform the following:

  • If a status reasoon phrase is invalid, it is dropped. Rendering is optional per spec.
  • If a header name is invalid in a request or response, the header is dropped. There is no way to generically sanitize a header without potentially shadowing a correct one.
  • If a header value is invalid in a request or response, it is sanitized by replacing null (\u0000), carriage return (\r), and newline (\n) with space () characters per spec.
  • If a URI path or registered name is invalid in a request line, the client raises an IllegalArgumentException.
  • If a URI registered name is invalid in a host header, the client raises an IllegalArgumentException.

Workarounds

http4s services and client applications should sanitize any user input in the aforementioned fields before returning a request or response to the backend. The carriage return, newline, and null characters are the most threatening.

Not all backends were affected: jetty-server, tomcat-server, armeria, and netty on the server; async-http-client, okhttp-client, armeria, and netty as clients.

References

  • https://owasp.org/www-community/attacks/HTTP_Response_Splitting
  • https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#fields.values

For more information

If you have any questions or comments about this advisory: * Open an issue in GitHub * Contact us via the http4s security policy

Show details on source website


{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.21.28"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-server"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.21.29"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.21.28"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-client"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.21.29"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.22.4"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-server"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.22.0"
            },
            {
              "fixed": "0.22.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.23.3"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-server"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.23.0"
            },
            {
              "fixed": "0.23.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.22.4"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-client"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.22.0"
            },
            {
              "fixed": "0.22.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.23.3"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-client"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.23.0"
            },
            {
              "fixed": "0.23.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2021-41084"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-74",
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-09-21T16:10:13Z",
    "nvd_published_at": "2021-09-21T18:15:00Z",
    "severity": "HIGH"
  },
  "details": "### Impact\n\nhttp4s is vulnerable to response-splitting or request-splitting attacks when untrusted user input is used to create any of the following fields:\n\n* Header names (`Header.name`\u00e5\n* Header values (`Header.value`)\n* Status reason phrases (`Status.reason`)\n* URI paths (`Uri.Path`)\n* URI authority registered names (`URI.RegName`) (through 0.21)\n\nThe following backends render invalid carriage return, newline, or null characters in an unsafe fashion.\n\n|                | blaze-server | ember-server | blaze-client | ember-client | jetty-client |\n|:---------------|:-------------|:-------------|:-------------|--------------|--------------|\n| header names   | \u26a0            | \u26a0            | \u26a0            | \u26a0            |   \u26a0            | \n| header values  | \u26a0            | \u26a0            | \u26a0            | \u26a0            |              |\n| status reasons | \u26a0            | \u26a0            |              |              |              |\n| URI paths      |              |              |  \u26a0             |  \u26a0             |              |\n| URI regnames   |              |              |  \u26a0 \u003c 0.22           |  \u26a0 \u003c 0.22            |              |\n\nFor example, given the following service:\n\n```scala\nimport cats.effect._\nimport org.http4s._\nimport org.http4s.dsl.io._\nimport org.http4s.server.blaze.BlazeServerBuilder\nimport scala.concurrent.ExecutionContext.global\n\nobject ResponseSplit extends IOApp {\n  override def run(args: List[String]): IO[ExitCode] =\n    BlazeServerBuilder[IO](global)\n      .bindHttp(8080)\n      .withHttpApp(httpApp)\n      .resource\n      .use(_ =\u003e IO.never)\n\n  val httpApp: HttpApp[IO] =\n    HttpApp[IO] { req =\u003e\n      req.params.get(\"author\") match {\n        case Some(author) =\u003e\n          Ok(\"The real content\")\n            .map(_.putHeaders(Header(\"Set-Cookie\", s\"author=${author}\")))\n        case None =\u003e\n          BadRequest(\"No author parameter\")\n      }\n    }\n}\n```\n\nA clean `author` parameter returns a clean response:\n\n```sh\ncurl -i \u0027http://localhost:8080/?author=Ross\u0027\n```\n\n```http\nHTTP/1.1 200 OK\nContent-Type: text/plain; charset=UTF-8\nSet-Cookie: author=Ross\nDate: Mon, 20 Sep 2021 04:12:10 GMT\nContent-Length: 16\n\nThe real content\n```\n\nA malicious `author` parameter allows a user-agent to hijack the response from our server and return different content:\n\n```sh\ncurl -i \u0027http://localhost:8080/?author=hax0r%0d%0aContent-Length:+13%0d%0a%0aI+hacked+you\u0027\n```\n\n```http\nHTTP/1.1 200 OK\nContent-Type: text/plain; charset=UTF-8\nSet-Cookie: author=hax0r\nContent-Length: 13\n\nI hacked you\n```\n\n### Patches\n\nVersions 0.21.29, 0.22.5, 0.23.4, and 1.0.0-M27 perform the following:\n\n* If a status reasoon phrase is invalid, it is dropped. Rendering is optional per spec.\n* If a header name is invalid in a request or response, the header is dropped.  There is no way to generically sanitize a header without potentially shadowing a correct one.\n* If a header value is invalid in a request or response, it is sanitized by replacing null (`\\u0000`), carriage return (`\\r`), and newline (`\\n`) with space (` `) characters per spec.\n* If a URI path or registered name is invalid in a request line, the client raises an `IllegalArgumentException`.\n* If a URI registered name is invalid in a host header, the client raises an `IllegalArgumentException`. \n\n### Workarounds\n\nhttp4s services and client applications should sanitize any user input in the aforementioned fields before returning a request or response to the backend.  The carriage return, newline, and null characters are the most threatening.\n\nNot all backends were affected: jetty-server, tomcat-server, armeria, and netty on the server; async-http-client, okhttp-client, armeria, and netty as clients.\n\n### References\n* https://owasp.org/www-community/attacks/HTTP_Response_Splitting\n* https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#fields.values\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue in [GitHub](http://github.com/http4s/http4s)\n* Contact us via the [http4s security policy](https://github.com/http4s/http4s/security/policy)\n",
  "id": "GHSA-5vcm-3xc3-w7x3",
  "modified": "2022-10-25T20:24:37Z",
  "published": "2021-09-22T19:18:41Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/http4s/http4s/security/advisories/GHSA-5vcm-3xc3-w7x3"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-41084"
    },
    {
      "type": "WEB",
      "url": "https://github.com/http4s/http4s/commit/d02007db1da4f8f3df2dbf11f1db9ac7afc3f9d8"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/http4s/http4s"
    },
    {
      "type": "WEB",
      "url": "https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#fields.values"
    },
    {
      "type": "WEB",
      "url": "https://owasp.org/www-community/attacks/HTTP_Response_Splitting"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Response Splitting from unsanitized headers"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
  • Confirmed: The vulnerability is confirmed from an analyst perspective.
  • Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
  • Patched: This vulnerability was successfully patched by the user reporting the sighting.
  • Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
  • Not confirmed: The user expresses doubt about the veracity of the vulnerability.
  • Not patched: This vulnerability was not successfully patched by the user reporting the sighting.


Loading…