diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-10 11:38:20 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-10 11:38:20 +0200 |
| commit | f1d706040785c90f114f80e7f45c597af06a03a9 (patch) | |
| tree | 32a0db3ee24bf6e3f22b971226fcbf984eddf685 /docs | |
| parent | 2611c6485fa733e627f2c62c0369260f3a96d0bc (diff) | |
| download | abusectl-f1d706040785c90f114f80e7f45c597af06a03a9.tar.gz abusectl-f1d706040785c90f114f80e7f45c597af06a03a9.zip | |
fix: emit only registered ARF fields, verified against IANA
Backlog item 4 asked for a primary source for the machine-readable part.
It exists, and it is IANA's MARF registry rather than x-arf's own docs.
Checked against that registry and RFC 5965 itself on 2026-09-10.
Report-Type is not a registered field. The registry lists 25 names and it
is absent; it came from this spec's worked example rather than a decision.
Removed, because Feedback-Type already says it. Keeping it would have been
harmless, since RFC 5965 section 6 makes ignoring an unknown field a MUST
for the receiver, but that same section requires an extension field be
registered, and a desk should be able to look up every field in a document
this tool sends.
Feedback-Type moves from abuse to fraud. RFC 5965 registers fraud as
"indicates some kind of fraud or phishing activity" and abuse as
"unsolicited email or some other kind of email abuse". This tool reports
phishing, and some desks route fraud separately from bulk spam.
Reported-Uri becomes Reported-URI, the spelling in the ABNF and the
registration. The RFC's own worked example uses the other one, which is
where this came from. Names are case-insensitive so nothing was broken.
A new test holds the registry's 25 names and asserts every emitted field
is one of them, with Source named as the single deliberate exception, so
a new unregistered field cannot arrive unnoticed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LByBnw83xr9YP85nskzkyE
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/BACKLOG.md | 55 | ||||
| -rw-r--r-- | docs/specs/2026-09-09-report.md | 13 |
2 files changed, 43 insertions, 25 deletions
diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 3ab642f..87ec4b3 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -8,7 +8,7 @@ number and gains a status rather than being renumbered. | 1 | Skip boilerplate namespace URLs | XS | open | | 2 | An IDN indicator resolves to no contact | S | open | | 3 | Expose kept cases so qtmaildir can tag spam | ? | open, unsized | -| 4 | `Report-Type: phishing` is unverified against x-arf | XS | open | +| 4 | `Report-Type: phishing` is unverified against x-arf | XS | closed | | 5 | `report.build()` raises KeyError on an identity with no email | XS | closed | ## 1. Skip boilerplate namespace URLs @@ -114,27 +114,38 @@ to qtmaildir. The second is much more in keeping with the rest of the tool. ## 4. `Report-Type: phishing` is unverified against x-arf -**Observed.** `report.feedback_fields()` emits `Report-Type: phishing` in the -machine-readable part. Every other field there was verified against RFC 5965 -itself; this one was not, because no primary source for x-arf's own field -semantics could be reached while building it. The abusix README documents only -the v3 to v4 deprecation and does not define the field. - -**Cause.** Not a defect found in the code. The value follows the worked -example in `docs/specs/2026-09-09-report.md`, so it is internally consistent, -and the hybrid envelope means a strict RFC 5965 parser ignores the field -either way (the RFC requires implementors ignore fields they do not support). -The exposure is limited to x-arf tooling reading a field name or value that -does not exist in the version it implements. - -**Approach.** Find a primary source for x-arf v4 field names, confirm or -correct the value, and record what it was checked against. If x-arf turns out -to name the field differently, the fix is one string and one test. - -**Constraints.** Low urgency: nothing here is a leak, and the failure mode is -a field an x-arf parser skips rather than acts on wrongly. Worth doing before -the first real report is filed, so a desk running x-arf tooling gets what it -expects. +**Closed** against the IANA MARF registry +(`https://www.iana.org/assignments/marf-parameters/marf-parameters.xml`), +checked 2026-09-10, plus RFC 5965 itself. The primary source the item asked +for exists; it is IANA's, not x-arf's. + +Two things were wrong, and neither was a leak. + +`Report-Type` is NOT a registered field. The registry lists 25 field names +and it is absent. It came from the worked example in the report spec rather +than from a decision. It is now REMOVED: `Feedback-Type` already carries what +it was saying. Keeping it would have been harmless, since RFC 5965 section 6 +makes ignoring an unknown field a MUST for the receiver, but that same section +requires an extension field be registered, and a desk should be able to look +up every field in a document this tool sends. + +`Feedback-Type` was `abuse` and is now `fraud`. RFC 5965 registers `fraud` as +"indicates some kind of fraud or phishing activity" and `abuse` as +"unsolicited email or some other kind of email abuse". This tool reports +phishing, so `fraud` is the registered value that says what the report is, +and some desks route it separately from bulk spam. + +A third, cosmetic, finding: the module emitted `Reported-Uri` while the RFC's +ABNF and its IANA registration both spell it `Reported-URI`. The RFC's own +worked example writes `Reported-Uri`, which is where the module's spelling +came from. Field names are case-insensitive per RFC 5322 so nothing was +broken, and it now matches the normative spelling. + +`tests/test_report.py::FeedbackPart::test_no_unregistered_field_is_emitted` +holds the registry's 25 names and asserts every emitted field is one of them. +The single exception is `Source`, which is x-arf's and is the reason the +envelope carries x-arf fields at all; it is named in the test so a NEW +unregistered field cannot arrive unnoticed. ## 5. `report.build()` raises KeyError on an identity with no email diff --git a/docs/specs/2026-09-09-report.md b/docs/specs/2026-09-09-report.md index 12d2157..b3a67ae 100644 --- a/docs/specs/2026-09-09-report.md +++ b/docs/specs/2026-09-09-report.md @@ -111,20 +111,27 @@ second body to keep in sync with the first for no reader. An RFC 5965 envelope carrying x-arf fields inside it. ``` -Feedback-Type: abuse +Feedback-Type: fraud User-Agent: abusectl/0.1.0 Version: 1 -Report-Type: phishing Source: 198.51.100.7 Source-IP: 198.51.100.7 Reported-Domain: example.invalid Arrival-Date: Mon, 08 Sep 2026 09:12:44 +0000 -Reported-Uri: http://login-example.invalid/verify?id=REDACTED +Reported-URI: http://login-example.invalid/verify?id=REDACTED ``` `Feedback-Type`, `User-Agent` and `Version` are the three fields RFC 5965 requires. The rest are optional there or come from x-arf. +**Every field name here is in the IANA MARF registry except `Source`**, which +is x-arf's and is the reason the envelope carries x-arf fields at all. An +earlier draft of this example also carried `Report-Type: phishing`, which is +not registered anywhere; it was removed once the registry was checked, since +`Feedback-Type` already says it. `fraud` rather than `abuse` because RFC 5965 +defines it as "some kind of fraud or phishing activity", which is what this +tool reports. See backlog item 4 for what was checked against what. + **Why an RFC 5965 envelope with x-arf fields inside, rather than either alone.** RFC 5965 is an IETF standard and universally understood, but it was designed for feedback loops, where a report is ABOUT A MESSAGE. These reports |
