curl/curl
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.
- `--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.
- 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.
- 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`).
- .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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- `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.
- 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)
- 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.
- 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.