SwiftNIO HTTP/2 Security Notice

All swift-nio-http2 users, please update to swift-nio-http2 version 1.5.0 urgently.

A number of HTTP/2 server implementations have been discovered to be at risk of a number of different denial of service attacks. SwiftNIO HTTP/2 has been affected by several of these vulnerabilities. This disclosure covers all of them.

All SwiftNIO HTTP/2 versions between 1.0.0 and 1.4.0 inclusive are affected.

SwiftNIO HTTP/2 is affected by:

  • CVE-2019-9512: Ping Flood

  • CVE-2019-9514: Reset Flood

  • CVE-2019-9515: Settings Flood

  • CVE-2019-9516: 0-length headers memory leak

  • CVE-2019-9518: Empty DATA frame flooding

Detailed Discussion

Ping Flood, Reset Flood, Settings Flood (CVE-2019-9512, CVE-2019-9514, CVE-2019-9515)

A SwiftNIO HTTP/2 server can be forced to buffer unbounded amounts of memory when flooded with control frames that require an automatic response. This occurs because SwiftNIO HTTP/2 will automatically write the response frame and send it down the Channel without checking whether the Channel is actually capable of sending the data. If the remote peer is not reading from the Channel, then the Channel will be forced to buffer these frames indefinitely. Done for a sufficiently long time this will lead to memory exhaustion and a process exit.

This attack is addressed by forcing control frames to be buffered inside the NIOHTTP2Handler. This allows us to keep track of the number of buffered control frames we have, and ensures that we can limit the number of outstanding frames, and drop the connection if that number exceeds a configured value.

0-length HEADERS leak (CVE-2019-9516)

A SwiftNIO HTTP/2 server had a number of vectors in which it would fail to validate the amount of resources it would grant the remote peer for decoding HPACK-encoded header blocks.

In the first instance, while SwiftNIO HTTP/2 advertised a maximum decoded header list size to peers, that size was never actually enforced. A remote peer could therefore get a SwiftNIO HTTP/2 server to consume an infinite amount of memory by sending a continuous stream of HEADERS/CONTINUATION frames. This was fixed by correctly enforcing the set value of SETTINGS_MAX_HEADER_LIST_SIZE.

In addition, SwiftNIO HTTP/2 was enhanced to forbid header fields with empty field names. As empty field names are forbidden by the HTTP RFCs, there is no reason to accept them here, and they are likely a symptom of an attempted denial of service attack.

Empty DATA frame flooding (CVE-2019-9518)

A SwiftNIO HTTP/2 server could be forced to consume substantial CPU resources by sending it an unbounded sequence of empty DATA frames that do not have END_STREAM set on them. These frames would not cause state transitions and would not be rate limited, so they could not easily be rejected automatically.

This attack was mitigated by adding heuristics that prevent sequences of empty DATA frames without END_STREAM set. Receiving multiple empty DATA frames in sequence will now cause connection teardown.

16 Likes

Credit for CVE-2019-9512, CVE-2019-9514, CVE-2019-9515, and CVE-2019-9516 goes to Jonathan Looney of Netflix. Credit for CVE-2019-9518 goes to Piotr Sikora of Google and the Envoy Security Team.

7 Likes

For those who are curious, a full writeup is available from Netflix.

6 Likes