| name | secure-email-validation |
| description | Generate secure email address validation code. Enforces secure generation of code validating an email address. Invoke when writing any email address validation related code. |
| allowed-tools | Read Grep Glob |
| metadata | {"category":"security"} |
Secure Email Address Validation Code Generation Rules
Apply all rules below when generating or reviewing any code related to validation of an email address.
1. Email address validation (CRITICAL)
- ALWAYS ensure that the email address is a valid email address, from a parser perspective, following RFCs on email addresses.
- ALWAYS ensure that the email address is not using "Encoded-word" format.
- ALWAYS ensure that the email address is not using comment format.
- ALWAYS ensure that the email address is not using "Punycode" format.
- ALWAYS ensure that the email address is not using UUCP style addresses.
- ALWAYS ensure that the email address is not using address literals.
- ALWAYS ensure that the email address is not using source routes.
- ALWAYS ensure that the email address is not using the "percent hack".
- ALWAYS enforce RFC 5321 length limits: local part ≤ 64 characters, domain ≤ 255 characters, total address ≤ 320 characters.
- ALWAYS ensure that the email address does not contain newline or carriage-return characters (CRLF injection prevention).
- ALWAYS ensure that the domain part contains at least one dot (reject single-label domains such as localhost or internal hostnames).
- ALWAYS ensure that the local part is not a quoted string (i.e. not wrapped in double quotes).
import jakarta.mail.internet.InternetAddress;
public static InternetAddress readEmailInsecure(String address) throws AddressException {
return new InternetAddress(address);
}
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
public static InternetAddress readEmailSecure(String email) throws AddressException {
if (email == null || email.isBlank()) {
throw new AddressException("Email address must not be null or blank");
}
InternetAddress address = new InternetAddress(email, true);
address.validate();
String raw = address.getAddress();
if (email.contains("=?") && email.contains("?=")) {
throw new AddressException("Encoded-word format is not allowed: " + email);
}
if (raw.contains("(") || raw.contains(")")) {
throw new AddressException("Comment format is not allowed: " + email);
}
String domain = raw.substring(raw.lastIndexOf('@') + 1);
if (domain.toLowerCase().contains("xn--")) {
throw new AddressException("Punycode format is not allowed: " + email);
}
if (raw.contains("!")) {
throw new AddressException("UUCP-style addresses are not allowed: " + email);
}
if (domain.startsWith("[") && domain.endsWith("]")) {
throw new AddressException("Address literals are not allowed: " + email);
}
if (email.startsWith("@")) {
throw new AddressException("Source routes are not allowed: " + email);
}
String localPart = raw.substring(0, raw.lastIndexOf('@'));
if (localPart.contains("%")) {
throw new AddressException("Percent hack is not allowed: " + email);
}
if (localPart.length() > 64) {
throw new AddressException("Local part exceeds 64 characters: " + email);
}
if (domain.length() > 255) {
throw new AddressException("Domain exceeds 255 characters: " + email);
}
if (raw.length() > 320) {
throw new AddressException("Email address exceeds 320 characters: " + email);
}
if (email.contains("\n") || email.contains("\r")) {
throw new AddressException("Newline characters are not allowed: " + email);
}
if (!domain.contains(".")) {
throw new AddressException("Single-label domains are not allowed: " + email);
}
if (localPart.startsWith("\"") && localPart.endsWith("\"")) {
throw new AddressException("Quoted local parts are not allowed: " + email);
}
return address;
}
2. Output Checklist
Before finalizing generated code, verify:
References