# Risk map — curl/curl

> Canonical page: https://codevetter.com/unpack/curl/risk-map

# Risk map — curl/curl

Scanned commit c362f034692e05ecb4d33edb740ba64c63a20add (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

curl's risk profile is dominated by the fact that it parses hostile input (URLs, headers, server responses, redirect targets) in C, on every platform, across dozens of optional backends. The highest-attention paths are credential handling (.netrc, `-u`, redirects that must drop auth), filename derivation from server-controlled `Content-Disposition`, the redirect/protocol allowlist, and the TLS/QUIC backend glue. Structurally, the biggest fragility is combinatorial: ~50 `CURL_DISABLE_*` knobs times six TLS backends times two QUIC backends times platform `#ifdef`s means many buildable configurations that no single CI job exercises. Blast-radius hotspots are the few central files every protocol funnels through — lib/multi.c, lib/url.c, lib/sendf.c, lib/cfilters.c — where a regression is not protocol-local.
- Server-controlled filenames reach the filesystem: `parse_filename()` in tool_cb_hdr.c strips path components and CR/LF, but the reserved-name / invalid-character sanitizer `sanitize_file_name()` is compiled only `#if defined(_WIN32) || defined(MSDOS)`, so POSIX hardening rests entirely on those `strrchr('/')`/`strrchr('\\')` trims. — [src/tool_cb_hdr.c#L185-L229](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_cb_hdr.c#L185-L229) [src/tool_doswin.h#L28-L35](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_doswin.h#L28-L35) [src/tool_doswin.c#L25-L27](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_doswin.c#L25-L27)
- `--output-dir` is applied by naive string concatenation (`curl_maprintf("%s/%s", config->output_dir, per->outfile)`) after the filename has been derived, so the safety of the combined path depends wholly on the earlier derivation step. — [src/tool_operate.c#L1099-L1110](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_operate.c#L1099-L1110)
- The protocol allowlist is enforced in exactly one place — `url_set_conn_scheme()` checking `data->set.allowed_protocols` and, for redirects, `data->set.redir_protocols` — making it a single point of failure for `--proto`/`--proto-redir` and for redirect-to-`file://` style attacks. — [lib/url.c#L1170-L1195](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/url.c#L1170-L1195)
- Credential-bearing code is spread across lib/creds.c, lib/netrc.c and lib/http.c's auth state machine (`Curl_http_output_auth`, `Curl_http_input_auth`, `http_perhapsrewind`, `Curl_http_auth_act`); the recent commit history shows this area actively hardened (e.g. keeping credentials out of `CURLINFO_REDIRECT_URL`). — [lib/creds.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/creds.c) [lib/http.c#L401-L560](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/http.c#L401-L560) [lib/http.c#L1066-L1180](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/http.c#L1066-L1180) [docs/internals/CREDENTIALS.md](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/docs/internals/CREDENTIALS.md)
- .netrc parsing is a hand-written lexer over an attacker-influenceable file with explicit hard caps — `MAX_NETRC_LINE` 16384, `MAX_NETRC_FILE` 128KB, `MAX_NETRC_TOKEN` 4096 — and a quoted-string state machine (`netrc_lexer_quoted`) that is worth re-reading before any change. — [lib/netrc.c#L68-L100](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/netrc.c#L68-L100) [lib/netrc.c#L194-L260](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/netrc.c#L194-L260)
- Interactive password entry disables terminal echo by clearing the `ECHO` bit in `termios` and must restore it on every exit path; a failure here leaks a typed password to the screen and to scrollback. — [src/tool_getpass.c#L110-L165](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_getpass.c#L110-L165)
- Several environment variables change behaviour without any command-line trace: `IPFS_GATEWAY`/`IPFS_PATH`/`HOME` in the tool, and `CURL_SSL_BACKEND` inside libcurl, which selects among compiled-in TLS backends at runtime. — [src/tool_ipfs.c#L40-L70](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_ipfs.c#L40-L70) [lib/vtls/vtls.c#L790-L820](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/vtls/vtls.c#L790-L820)
- DoH creates additional easy handles that perform their own network transfers with their own option set (`ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_probe_write_cb)` etc.); any option not deliberately propagated to the probe is silently not applied to DNS traffic. — [lib/vdns/doh.c#L234-L400](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/vdns/doh.c#L234-L400) [lib/vdns/doh.c#L403-L490](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/vdns/doh.c#L403-L490)
- Explicitly-experimental surface is documented as out of scope for security handling: the quiche QUIC backend and HTTP/3 proxy / CONNECT-UDP support are experimental, and docs/EXPERIMENTAL.md states vulnerabilities in experimental features are treated as ordinary bugs. — [docs/EXPERIMENTAL.md#L9-L50](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/docs/EXPERIMENTAL.md#L9-L50)
- Size is itself a risk in the hot files: lib/http.c is 5,112 lines, lib/multi.c 4,262, lib/ftp.c and lib/http2.c are next; `multi_runsingle()` alone dispatches thirteen states and is the path every protocol takes. — [lib/http.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/http.c) [lib/multi.c#L2714-L2890](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/multi.c#L2714-L2890) [lib/ftp.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/ftp.c)
- The `CURL_DISABLE_*` matrix (documented across ~50 entries in docs/CURL-DISABLE.md, from `CURL_DISABLE_ALTSVC` to `CURL_DISABLE_NETRC`) means many code paths are conditionally compiled; `scripts/randdisable` exists precisely because the full matrix cannot be CI-covered. — [docs/CURL-DISABLE.md#L9-L130](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/docs/CURL-DISABLE.md#L9-L130) [scripts/randdisable](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/scripts/randdisable)
- `Curl_fopen()` gets the durable-write pattern right (O_EXCL temp file, 0600, `fchmod` clone only when uid/gid match, then rename), so any new cache writer that bypasses it loses those properties — a coupling that is easy to miss. — [lib/curl_fopen.c#L78-L150](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/curl_fopen.c#L78-L150) [lib/hsts.c#L369-L400](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/hsts.c#L369-L400) [lib/altsvc.c#L392-L425](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/altsvc.c#L392-L425)
- Parallel mode's abort path is cooperative rather than immediate: `wrapitup` only sets `per->abort`, and the transfer does not stop until its progress callback next fires — so a stalled transfer can outlive a `--fail-early` decision. (inferred) — [src/tool_operate.c#L2038-L2060](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_operate.c#L2038-L2060) [src/tool_operate.c#L1919-L1926](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_operate.c#L1919-L1926)
- The libuv-based event loop used by `--parallel` under `test_event_based` is `#if defined(DEBUGBUILD) && defined(USE_LIBUV)` only, so `parallel_event()`, `on_uv_socket()`, `cb_socket()` and `destroy_context()` are never exercised by a release build. — [src/tool_operate.c#L1672-L1902](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_operate.c#L1672-L1902)
- libcurl defends against API misuse at runtime rather than at compile time: magic-number checks (`CURLEASY_MAGIC_NUMBER`, `CURLMULTI_MAGIC_NUMBER`) and a call-stack guard that returns `CURLE_RECURSIVE_API_CALL` when an application re-enters the API from inside a callback. — [lib/api.h#L3-L60](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/api.h#L3-L60) [lib/easy.c#L813-L816](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/lib/easy.c#L813-L816)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
