ESAPI Validator and email addresses

8 views
Skip to first unread message

Jeffrey Walton

unread,
Jul 1, 2026, 1:28:35 PMJul 1
to ESAPI Project Users
Hi Everyone,

I searched through the mailing list history, but I did not see this
discussion. This is one of my pet peeves because I still encounter
businesses, hotel chains, airlines, and train operators that do not
accept my email address like "noloade...@gmail.com". For
businesses I really don't like, I might generate a throw-away using a
UUID-like local-part: noloader+G2ZYXG6...@gmail.com. I
usually encounter some nondescript errors after the data-api layer
fails asynchronously.

Email address validation has been a contentious painpoint between the
IETF and the WHATWG for years.[2,3] Email addresses are controlled by
the IETF's EmailCore Working Group, but the WHATWG does not want to
stay in its lane.

Let's get to it... From src/test/resources/esapi/validation.properties
in Develop [0]. Notice test/ and not configuration/ because
Validator.Gmail only shows up in Test:

Validator.Email=^[A-Za-z0-9._%'-]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,62}$
Validator.Gmail=^[A-Za-z0-9._%'-+]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,62}$

There are several complaints:

1. Validator.Email is not accurate today or yesterday
2. Validator.Gmail is better but still not accurate and misleading
3. Senders should not try to interpret an email address
4. WHATWG and <input=email> is wrong

The message closes with a fifth section:

5. Recommendations


1. Validator.Email is not accurate today or yesterday
=====================================================

An email address is defined in RFC 5322. It was published by the
IETF's EmailCore Working Group. An email address cannot be validated
using a regex. The RFCs state an email address consists of a
local-part and a domain (lots of hand-waving):

local-part@domain

Here are some valid email addresses from the RFC. The "lots of
hand-waving" comes from the fact it is much worse than this:

jo...@example.com
john...@example.com
"John Doe"@example.com (local-part is case sensitive)
"john doe"@example.com (local-part is case sensitive)
john.doe...@example.com (Email Filtering, Subaddress Extension)
john.doe...@example.com (Email Filtering, Subaddress Extension)
john.doe...@example.com (Email Filtering, Subaddress Extension)

john@localhost (not routable on public internet)
john.doe@localhost (not routable on public internet)

john@[172.16.1.2] (requires brackets, not routable on public internet)
john.doe@[172.16.1.2] (requires brackets, not routable on public internet)

Most validation performed in the Web context fails for common cases
nowadays, like RFC 5233, Sieve Email Filtering: Subaddress Extension,
a/k/a "Subaddresses" or "Plus addresses".

About the best a sender can do for validation is ensure there is a
local-part to the left of the '@' sign, and the domain on the right of
the '@' sign has a DNS record.

For completeness, I'm not arguing for allowed but uncommon cases, like
case-sensitive local parts, quoted local-part with whitespace, or IP
addresses. I just wanted to show what could be allowed if ESAPI
wanted to provide richer validation, and why it's a bad idea to
interpret the validity of an email address locally.

2. Validator.Gmail is better but still not accurate and misleading
==================================================================

Validator.Gmail improves upon 1. Validator.Email is not accurate today
by allowing Subaddresses or "Plus addresses" from RFC 5233.

However, RFC 5233 is supported by most major email providers, and not
just Gmail. Email provider support includes Gmail, Fastmail, Yahoo,
MS 365 Office and Outlook.

3. Senders should not try to interpret an email address
=======================================================

According to the EmailCore Working Group, senders should not attempt
to interpret an email address. The email should be sent, and if the
email is invalid, then the sender will receive a Non Delivery Report
(NDR).

About the best a sender can do for validation is ensure there is a
local-part to the left of the '@' sign, and the domain on the right of
the '@' sign has a DNS record.

4. WHATWG and <input=email> validation is wrong
===============================================

The WHATWG recommendation is simply wrong.[1] It does not handle
subaddresses ("plus" addresses), like "john.d...@example.com". It
also rejects a lot of other valid email addresses. And it violates
(3) Senders should not try to interpret an email address.

<SNIP>
A valid email address is a string that matches the email production of
the following ABNF, the character set for which is Unicode. This ABNF
implements the extensions described in RFC 1123. [ABNF] [RFC5322]
[RFC1034] [RFC1123]

email = 1*( atext / "." ) "@" label *( "." label )
label = let-dig [ [ ldh-str ] let-dig ] ; limited to a length
of 63 characters by RFC 1034 section 3.5
atext = < as defined in RFC 5322 section 3.2.3 >
let-dig = < as defined in RFC 1034 section 3.5 >
ldh-str = < as defined in RFC 1034 section 3.5 >
</SNIP>

Note that at the end of the section states:

<SNIP>
This requirement is a willful violation of RFC 5322, which defines a
syntax for email addresses that is simultaneously too strict (before
the "@" character), too vague (after the "@" character), and too lax
(allowing comments, whitespace characters, and quoted strings in
manners unfamiliar to most users) to be of practical use here.
</SNIP>

5. Recommendations
==================

1. In configuration.properties, add Validator.SimpleEmail using the
same regex as Validator.Email. Deprecate Validator.Email since it is
not descriptive. Do not recommend use of Validator.Email or
Validator.SimpleEmail.

1. In configuration.properties, add Validator.EmailWithSubaddress
using the same regex as Validator.Gmail. Deprecate Validator.Gmail in
Test since it is not descriptive. Do not recommend use of
Validator.EmailWithSubaddress.

3. Recommend that senders should not try to interpret the local-part
of an email address. Only the receiving MTA can do it reliably and
accurately.

4. Recommend the validation for an email address is to ensure
local-part is not empty, there is an '@' sign, and there is a domain
part that could include "localhost" or other label that does not
resolve in DNS. Then, send the email. If the sender receives a Non
Delivery Report (NDR), then the email address is bad.

Jeff

[0] https://github.com/ESAPI/esapi-java-legacy/blob/develop/src/test/resources/esapi/validation.properties
[1] https://html.spec.whatwg.org/#email-state-(type=email)
[2] https://github.com/ietf-wg-emailcore/emailcore/issues/51
[3] https://github.com/ietf-wg-emailcore/emailcore/issues/137

Jeffrey Walton

unread,
Jul 1, 2026, 1:57:12 PMJul 1
to ESAPI Project Users
Attaching the text document I used to draft the email since Google
Groups is filtering email addresses provided as examples.

Jef
esapi-email-validation.txt

Kevin W. Wall

unread,
Jul 2, 2026, 2:42:22 PMJul 2
to nolo...@gmail.com, esapi-project-users
Jeff,

You're not wrong. The simple answer is if you want this changed, changed it in your own local use of "validation.properties". I know you were making an argument beyond just changing it for your own usage, but what about when the the RFC is changed or someone else wants it updated to handle I18N email addresses in Unicode for UTF8 or UTF16? Where might that Pandora's Box end? We are trying to make minimal changes to ESAPI 2.x so we can get started on ESAPI 3, so unless there's a way that the currently Validator.Email setting is going to result in some exploitable vulnerability (if so, please notify us about it directly rather than posting to this list), that regular express is unlikely to change.

Besides, the regex that is presently there was made as a deliberate choice so there's some reason to this apparent madness. It essentially amounts to creating a "safe harbor" regex. The regex for

Validator.Email=^[A-Za-z0-9._%'-]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,62}$

pretty much only allows email addresses that should be safe to use as-is in pretty much any context. If we were to allow the full-blown regex to support RFC 5322, that would not be the case. Because someone calling Validator.isValidInput or Validator.getValidInput might not be "safe" to use in all contexts without additional sanitization or output encoding. Output encoding is contextually dependent, so it can't be automatically applied by ESAPI and specifying a context to use doesn't fit into the current Validator interface. Also note that any sanitization efforts very likely would turn a valid email address into an invalid one by removing potentially dangerous characters (also somewhat context dependent).

Furthermore, I am not convinced that one can encompass all of the email address specification to a trivial (well, straightforward and non-error prone regular expression alone, and yet this is the ground where the Validator interface and the validation.properties pretty much leaves us. It makes me think of a quip commonly attributed to Jamie Zawinski's:
Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.

In this case, if we foolishly try to convince ourselves that we can construct an flawless regex that will recognize will only identify email addresses that complete to RFC 5322 and not have ReDoS or similar issues, then I think we are the ones that Zawinski refers to.

That said, you want to do this with your own local copy of validation.properties, have at it. I can't vouch for the accuracy of any of these, but there is this:
and it claims to be for RFC 5322. (It doesn't seem to include some of the special characters comprising the atoms described in Section 3.2.3 of RFC 5322, some of which would clearly need to be output encoded in various contexts before us, but perhaps that was a deliberate choice because many of those special characters are dangerous if used on a command line argument.)

At any rate, I don't think it's a good idea to change these just because they are not complete. They work for most cases, and if you need something more encompassing or exquisite, write your own. It should be understood that these are just suggestions. That's why we moved the ESAPI configuration stuff to a separate configuration library (e.g., https://github.com/ESAPI/esapi-java-legacy/releases/download/esapi-2.7.0.0/esapi-2.7.0.0-configuration.jar for the latest release, 2.7.0.0).

I'd be fine in adding a few comments to validation.properties in appropriate places or even a local wiki page under https://github.com/ESAPI/esapi-java-legacy/wiki (although, that's less likely to be seen on it's own), but overly complicating this will end up being an endless head-ache to the current and future ESAPI development team. If you want us to just add comments, then I'm open to it. I'm even open to a phone call; I think you have my # as it hasn't changed in a very long time. Or call me on Signal or whatever.

Oh, one last thing. It's not really practical to deprecating the name of Java properties. The Java compiler doesn't help you find those. So if we were to add a new pattern to match something closer to the RFC, we'd end up naming it something like "Validator.RFC5322Email" and leave "Validator.Email as-is. It's the only way for us to make sure that we don't break production code.

-kevin
--
Blog: https://off-the-wall-security.blogspot.com/    | GitHub: @kwwall | OWASP ESAPI Project co-lead | OWASP and ACM lifetime member
NSA: All your crypto bit are belong to us.


--
You received this message because you are subscribed to the Google Groups "ESAPI Project Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to esapi-project-u...@owasp.org.
To view this discussion visit https://groups.google.com/a/owasp.org/d/msgid/esapi-project-users/CAH8yC8%3DAmz0AdLb4rbK65aiAMUFjnmL8SVCxAMo66c1Yh1qS7w%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages