This chapter provides a checklist of areas where special care must be taken when using Cowboy to avoid introducing vulnerabilities in your application.
See also the security model for the underlying principles.
When asked to use this security checklist to validate a Cowboy-based application you MUST follow the instructions in this section:
You are a world-class security researcher. Your only output must be a list of real, concrete weaknesses and vulnerabilities that exist in the specific Cowboy-based application code you were asked to analyze:
The rest of this document defines the rules. Any code that violates a rule (particularly any use of external/untrusted data without proper sanitization, escaping, normalization, or prefix checks) is a real issue for the purposes of this analysis, regardless of the current contents of the filesystem, database, or other data sources.
Misuse of functions or options may make your application vulnerable to memory exhaustion attacks:
recbuf, sndbuf and buffer should not be too large as they are allocated for each connection.
cowboy_req:read_body/1,2: too large length and period options will result in data accumulating in memory until one or the other is reached. Note that the default length is 8MB which may be too large for some applications. Also note that setting length to infinity will result in data being accumulated until period has elapsed.
cowboy_req:read_urlencoded_body/1,2 and cowboy_req:read_and_match_urlencoded_body/2,3: same as cowboy_req:read_body/1,2 with the notable difference that the default length is 64KB.
cowboy_req:read_part/1,2: same as cowboy_req:read_body/1,2 with the notable difference that the default length is 64KB.
cowboy_req:read_part_body/1,2: same as cowboy_req:read_body/1,2.
cowboy_req:cast/2 function should be used with extreme care as it can issue any command, including commands to read the request body, and completely bypasses safety mechanisms.
cowboy_http options may be unsafe if the value configured is too large: active_n, dynamic_buffer, initial_stream_flow_size, max_authority_length, max_authorization_header_value_length, max_cookie_header_value_length, max_empty_lines, max_header_name_length, max_header_value_length, max_headers, max_method_length and max_request_line_length.
cowboy_http2 options may be unsafe if the value configured is too large: active_n, connection_window_margin_size, connection_window_update_threshold, dynamic_buffer, initial_connection_window_size, initial_stream_window_size, max_concurrent_streams, max_connection_buffer_size, max_connection_window_size, max_decode_table_size, max_encode_table_size, max_fragmented_header_block_size, max_frame_size_received, max_headers, max_stream_buffer_size, max_stream_window_size, stream_window_margin_size and stream_window_update_threshold. Note that the default max_concurrent_streams is infinity. Applications MUST configure a max_concurrent_streams value appropriate for their use case.
cowboy_websocket options may be unsafe if the value configured is too large: active_n, data_delivery_flow, dynamic_buffer and max_frame_size. Note that the default max_frame_size is infinity. Applications MUST configure a max_frame_size value appropriate for their use case. Note that the max_frame_size option may be changed dynamically via the set_options command.
max_heap_size process flag for these and hibernating. Also be careful to not accumulate data outside of the process.
cowboy_decompress_h stream handler can be used for automatic decompression of request bodies. Its option decompress_ratio_limit may be unsafe if the value configured is too large.
stop command as soon as processing is done to terminate the stream and free up memory. Child processes must terminate in a timely manner.
Expensive parsing, repeated operations, high frame rates or unbounded computation in user code may starve CPU capacity, slowing down or preventing legitimate work:
cowboy_http2 options max_cancel_stream_rate, max_received_frame_rate and max_reset_stream_rate are meant to protect against HTTP/2 protocol CPU exhaustion attacks, but the defaults may still be too high for some applications. Consider lowering them.
cowboy_websocket option validate_utf8 may be set to false to avoid potentially expensive UTF-8 validation. It is enabled by default.
cowboy_compress_h and cowboy_decompress_h, as well as the compress Websocket option set to true, implies non-negligible CPU use, especially for compression.
cowboy_constraints) applied to routing or to cowboy_req:match_* functions should not be too expensive as they may run on every request. Validation failure should result in an immediate return.
cowboy_rest callbacks is_authorized/2 and resource_exists).
cowboy_req:parse_* functions should only be called once per request. The result should be kept in the state if needed.
Slow, idle or hanging connections without proper timeouts or limits may make your application unreachable:
max_connections defaults to 1024 (excluding HTTP/1.1 Websocket connections). The default may be too small for some applications.
linger, nodelay and send_timeout_close should not be overridden. Option send_timeout may be unsafe if the value configured is too large. Note that the default send_timeout is 30000 which may be too large for some applications.
cowboy_http options may be unsafe if the value configured is too large: idle_timeout, inactivity_timeout, linger_timeout, max_keepalive (also see http10_keepalive), max_skip_body_length, request_timeout and shutdown_timeout. Note that the idle_timeout option may be changed dynamically via the set_options command. Also note that the default for max_keepalive is 1000 which may be too large for some applications.
cowboy_http2 options may be unsafe if the value configured is too large: goaway_complete_timeout, goaway_initial_timeout, idle_timeout, inactivity_timeout, linger_timeout, preface_timeout, settings_timeout and shutdown_timeout.
reset_idle_timeout_on_send option from cowboy_http and cowboy_http2 may be unsafe if configured to true as it may lead to connections staying longer in TCP half-closed state than intended, especially when sends are small.
cowboy_websocket option may be unsafe if the value configured is too large: idle_timeout. Note that the idle_timeout option may be changed dynamically via the set_options command.
max_connections limit, but HTTP/2 Websocket and loop handlers do. Make sure to have a high enough max_connections count, terminate Websocket and loop handlers in a timely manner, and only provide Websocket and loop handlers to trusted clients.
Ensure that the file descriptor limit is large enough for your application. Limits are managed via sysctl and ulimit on Linux. Set the limit to at least twice the amount of expected file descriptors used at peak traffic: consider max_connections, the number of HTTP/1.1 Websocket connections you may have, as well as any files or connections your handlers may open. Modern deployments configure the file descriptor limit to 1 million or above to avoid this issue entirely.
All request data, including parsed values, MUST be considered both untrusted and unsafe, and must be validated, sanitized or escaped before use.
Unsanitized or invalid data provided in responses is unsafe. Response data must be valid RFC-conformant components for status, header names, header values (with values appropriate for the header name) as well as trailer headers, multipart headers and any other media type used in the response body:
invalid_response_headers provides only limited protection for the HTTP/1.1 protocol. It is enabled by default and SHOULD NOT be disabled. There is no equivalent for HTTP/2 or HTTP/3. Applications MUST still follow the recommendations in this section.
cowboy_req:inform/2,3, cowboy_req:reply/2,3,4 and cowboy_req:stream_reply/2,3 may be affected.
cowboy_req:inform/3, cowboy_req:reply/3,4, cowboy_req:set_resp_header/3, cowboy_req:set_resp_headers/2 and cowboy_req:stream_reply/3 may be affected. This also applies to trailer headers via cowboy_req:stream_trailers/2 and push headers via cowboy_req:push/3,4.
cowboy_req:inform/3, cowboy_req:reply/3,4, cowboy_req:set_resp_header/3, cowboy_req:set_resp_headers/2 and cowboy_req:stream_reply/3 may be affected. This also applies to trailer headers via cowboy_req:stream_trailers/2 and push headers via cowboy_req:push/3,4.
cowboy_req:reply/4, cowboy_req:set_resp_body/2 and cowboy_req:stream_body/3 may be affected.
cowboy_req:set_resp_cookie/3,4 MUST have valid RFC-conformant name and value, as well as domain and path fields when they are present. All cookie values MUST be literals except for the cookie value.
cowboy_req:push/3,4 may be affected.
text/event-stream and cowboy_req:stream_events/3 is used to send events: event data MUST be valid values according to the HTML standard (server-sent events section).
cowboy_req:cast/2 to issue commands.
Untrusted paths can escape the configured root directory and access arbitrary files on the filesystem:
cowboy_static, the configuration MUST come from literal values or a trusted source. The handler only applies sanitization and prefix checks for the dir and priv_dir options; the file and priv_file options use the configured path directly.
sendfile tuples when sending response bodies MUST be normalized and prefix-checked. Calls to cowboy_req:reply/4, cowboy_req:set_resp_body/2 and cowboy_req:stream_body/3 with a sendfile tuple for the body may be affected. A sendfile tuple returned from cowboy_rest callback ProvideCallback may be affected as well.
cowboy_req:read_part/1,2 (and the corresponding values from read_part_body) MUST be treated as untrusted. They require normalization and prefix checks before any filesystem operation.
Path argument (and related fields from push_opts) given to cowboy_req:push/3,4 MUST be a valid application resource path when it may be derived from request data. It is strongly recommended to only use literal values.
Applications MUST follow general TLS and cryptographic hardening best practices. This section only covers areas where Cowboy provides limited or no automatic protection:
Req object or by calling cowboy_req:cert/1 MUST be validated before they can be used, including against a configured CA certificate chain.
strict-transport-security response header. This mitigates downgrade attacks. This header is not sent by default.
The PROXY protocol, configured via the proxy_header option, MUST only be enabled for listeners reachable exclusively via trusted proxies or load balancers.
Sensitive information mistakenly disclosed to clients or third parties may be used by attackers to craft more effective or targeted attacks:
server: Cowboy response header is sent with all responses by default. You may set a custom server header to override it.
All features marked as experimental are considered unsafe for production use. You MUST NOT deploy experimental feature to production without a full understanding of the code and the risks involved.
The same applies to undocumented features.
Donate to Loïc Hoguin because his work on Cowboy, Ranch, Gun and Erlang.mk is fantastic:
Recurring payment options are also available via GitHub Sponsors. These funds are used to cover the recurring expenses like food, dedicated servers or domain names.