diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-09 19:38:18 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-09 19:38:18 +0200 |
| commit | 2aa840e2ce75a04628085ccecd6382f8e5e9734a (patch) | |
| tree | 5815dd2dca3dc256d1e8e39698ac3597aa9e58f7 /docs/plans/2026-09-08-parse.md | |
| parent | f1b37bc5dea7493a6d98e552c48cb6e6f9f3f0ec (diff) | |
| download | abusectl-2aa840e2ce75a04628085ccecd6382f8e5e9734a.tar.gz abusectl-2aa840e2ce75a04628085ccecd6382f8e5e9734a.zip | |
feat: build the machine-readable feedback report part
An RFC 5965 envelope carrying x-arf fields. 5965 reports are about a message
and these are about indicators, so x-arf's Source fills the gap while the
report-type keeps a standards parser working.
Field values are percent-encoded against header injection. This is reachable,
not theoretical: redact.url_valued_parameters() URL-decodes a redirector's
destination to recover it as an indicator, so a body carrying
"?next=http%3A%2F%2Fa.invalid%2Fx%0AFeedback-Type%3A%20not-abuse" produces,
through parse.iocs() on a real message, an IOC whose value holds a literal
newline followed by text shaped like a field. Emitted verbatim it forges a
field in a report carrying the reporter's identity. Encoding rather than
dropping keeps a genuine redirect target; encoding rather than stripping
keeps the indicator recoverable, since a stripped URL is a different URL a
desk would then act on. The escape covers everything str.splitlines() breaks
on, because Python's own email module raises on U+2028 as readily as on LF,
and it runs over UTF-8 bytes and escapes "%" so the reversal is a true
inverse rather than a second injection one step later.
Four corrections to the plan. Source-IP is emitted once, not once per IP:
RFC 5965 gives it "once maximum" and a repeat displaces the primary rather
than adding an address. Source is omitted when there is no typed indicator
rather than emitted empty, since an empty field asserts that the reported
thing is the empty string. Arrival-Date is dropped rather than copied from
the sender's Date header, which is attacker-controlled and means when the
sender claimed to send, not when our MTA received. sha256 and observation
are left to the text part rather than forced into the nearest field.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xj1ayFRSUQ2u7cwb3S4axE
Diffstat (limited to 'docs/plans/2026-09-08-parse.md')
0 files changed, 0 insertions, 0 deletions
