This is an automated email from the ASF dual-hosted git repository. chibenwa pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-jspf.git
commit 803d0395c10d12c9289b3a7c44273dfcb4c8afb3 Author: Quan Tran <[email protected]> AuthorDate: Thu Nov 5 10:33:42 2026 +0700 [FIX] SPFRetriever: discard a record not beginning with v=spf1 A record was selected when it began with "v=spf1" once trimmed, so " v=spf1 +all", with a leading space, counted as an SPF record: next to "v=spf1 -all" the check gave permerror for two records, and alone it was selected before the record of the obsolete SPF type. RFC 7208 4.5 discards "records that do not begin with a version section of exactly "v=spf1"", which a space or the end of the record ends. Compare the record as it is, ignoring case only. --- .../apache/james/jspf/policies/SPFRetriever.java | 4 ++-- .../org/apache/james/jspf/SPFExecutorBaseTest.java | 27 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/resolver/src/main/java/org/apache/james/jspf/policies/SPFRetriever.java b/resolver/src/main/java/org/apache/james/jspf/policies/SPFRetriever.java index 765f15e..57d2df7 100644 --- a/resolver/src/main/java/org/apache/james/jspf/policies/SPFRetriever.java +++ b/resolver/src/main/java/org/apache/james/jspf/policies/SPFRetriever.java @@ -126,8 +126,8 @@ public class SPFRetriever implements SPFChecker { // DO NOT trim the result! String compare = all.next(); - // We trim the compare value only for the comparison - if (compare.toLowerCase().trim().startsWith(SPF1Constants.SPF_VERSION1 + " ") || compare.trim().equalsIgnoreCase(SPF1Constants.SPF_VERSION1)) { + // RFC 7208 4.5: a record begins with exactly "v=spf1", ended by a space or by the end of the record + if (compare.toLowerCase().startsWith(SPF1Constants.SPF_VERSION1 + " ") || compare.equalsIgnoreCase(SPF1Constants.SPF_VERSION1)) { if (returnValue == null) { returnValue = compare; } else { diff --git a/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java b/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java index 98057a5..b5d6f3c 100644 --- a/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java +++ b/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java @@ -944,6 +944,33 @@ public abstract class SPFExecutorBaseTest { assertEquals(SPFErrorConstants.TEMP_ERROR_CONV, result.getResult()); } + @Test(timeout = 10000) + public void shouldDiscardARecordThatDoesNotBeginWithTheVersion() throws IOException { + String hostname = "leadingSpace.spfexecutor.fake"; + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + "."), DClass.IN, 30L, "v=spf1 -all")); + fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + "."), DClass.IN, 30L, " v=spf1 +all")); + SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver)); + + SPFResult result = spf.checkSPF("192.0.2.10", "a_user@" + hostname, hostname); + + // RFC 7208 4.5: "discard records that do not begin with a version section of exactly "v=spf1"" + assertEquals(SPFErrorConstants.FAIL_CONV, result.getResult()); + } + + @Test(timeout = 10000) + public void shouldReadTheSpfTypeWhenNoTxtRecordBeginsWithTheVersion() throws IOException { + String hostname = "leadingSpaceOnly.spfexecutor.fake"; + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + "."), DClass.IN, 30L, " v=spf1 +all")); + fakeResolver.addRecord(new SPFRecord(Name.fromString(hostname + "."), DClass.IN, 30L, "v=spf1 -all")); + SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver)); + + SPFResult result = spf.checkSPF("192.0.2.10", "a_user@" + hostname, hostname); + + assertEquals(SPFErrorConstants.FAIL_CONV, result.getResult()); + } + @Test(timeout = 10000) public void shouldCheckTheTxtRecordWhenTheLookupOfTheSpfTypeFails() throws IOException { String hostname = "spftypeservfail.spfexecutor.fake"; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
