Vulnerability analysis · SPF evaluation
An SPF evaluation that ends in an error allocates a buffer and never gives it back. Destroying the response does not free it, so each malformed record costs the process a little memory.
| Software | libspf2 |
|---|---|
| Vendor | libspf2 maintainers |
| Source | https://github.com/shevek/libspf2 |
| Affected | Current upstream master; the Debian package 1.2.10-8.3 was present in the test environment. Newest published release checked on 2026-07-30. |
| Where | SPF_response_add_error() error path; the allocated error buffer is not freed when the SPF_response is destroyed |
| Weakness | CWE-401 (Missing Release of Memory after Effective Lifetime) |
| Reachable by | Remote. Each evaluation of a malformed SPF record leaks; the record is published by the sending domain. |
| CVSS v3.1 | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L (5.3 (Medium)) |
| Verification | LeakSanitizer-confirmed via the SPF interpretation harness over a malformed-record corpus. |
SPF_response_add_error() allocates a buffer to hold the error text it records against an SPF_response. The teardown path for that response does not free the buffer. Every SPF evaluation that ends in an error therefore costs the process one small allocation that is never returned.
A receiver that evaluates SPF records supplied by senders repeats that cost once per malformed evaluation. Under sustained malformed traffic the growth is unbounded.
LeakSanitizer attributes the allocation to the error path directly:
==ERROR== LeakSanitizer: detected memory leaks
Direct leak of N byte(s) in M object(s) allocated from:
... SPF_response_add_error ...
Only the error path leaks. A well-formed record is evaluated and torn down cleanly. To reach the leak an attacker has to make the evaluation fail, and publishing a malformed SPF record for a domain they control does exactly that.
export BUILD="$HOME/asan-build"
bash lib/build_spf.sh # builds fuzz_spf_compile and fuzz_spf_interp
a single error-path input.
ASAN_OPTIONS=detect_leaks=1 "$BUILD/fuzz_spf_interp" corpus_spf/
# or a single error-path input:
ASAN_OPTIONS=detect_leaks=1 "$BUILD/fuzz_spf_interp" memory-safety/seeds/L1-spf-leak
The exposed party is any long-lived process that evaluates SPF over records it did not write. The attacker needs no authentication and no position on the network path. The record is published from a domain they control, so the input is entirely theirs. What they get is gradual memory growth, ending in exhaustion.
The rating is low because volume is required. One malformed evaluation costs almost nothing, and the impact only becomes material after a sustained stream of them.
Free the error buffer on every SPF_response teardown path.
This is a leak and nothing more. No corruption was observed, and this is the lowest severity in the reporting set.
Two items remain open before vendor contact. The leak has not been re-confirmed against the current libspf2 release. There is also no minimized single input pinning the exact error term; the confirmation so far rests on the corpus.