Guard IMAP Command
IMAP command-line validator (RFC 9051 IMAP4rev2; obsoletes RFC 3501). Gates every command-line the framework's inbound IMAP listener accepts from peers — CAPABILITY / NOOP / LOGOUT / STARTTLS / AUTHENTICATE / LOGIN / ENABLE / SELECT / EXAMINE / CREATE / DELETE / RENAME / SUBSCRIBE / UNSUBSCRIBE / LIST / NAMESPACE / STATUS / APPEND / IDLE / CHECK / CLOSE / UNSELECT / EXPUNGE / SEARCH / FETCH / STORE / COPY / MOVE / UID / GETQUOTA / SETQUOTA / GETQUOTAROOT / ID.
## Smuggling defense — bare-CR / bare-LF refusal
Same wire-protocol smuggling class as SMTP: implementations that accept bare-CR or bare-LF in a command line let a hostile peer inject a second command past a per-line filter. RFC 9051 §2.2.1 requires CRLF only; this validator refuses every bare CR / bare LF / NUL / C0 / DEL byte outside of explicit literal blocks (which the wire-protocol reader has already framed before handing the line to this validator).
## Literal-injection defense
IMAP carries inline length-prefixed literals: {n}. Per RFC 9051 §2.2.2 the literal opener {n} MUST appear at the end of a command line, with the n bytes following on subsequent line(s). RFC 7888 LITERAL+ relaxes the round-trip but is only honored post-AUTH. The validator detects literal openers as either:
- well-formed:
{42}or{42+}at the end of the line - injected:
{42}mid-line (smuggling shape — refuse)
Per-literal byte cap defaults to 64 MiB (operator opts down via maxLiteralBytes); the LISTENER then enforces the post-literal read against this cap.
## Mailbox-name traversal
Mailbox names per RFC 9051 §5.1 — UTF-8 hierarchy with the server-chosen delimiter (typically / or .). Refuses path- traversal (..), NUL bytes, control chars, leading/trailing slash, overlong UTF-8 sequences, and (under strict) modified- UTF7 (RFC 3501 §5.1.3 legacy encoding — operators with legacy MUAs opt in via allowLegacyMUtf7).
## Per-verb shape
Each command verb has a fixed argument shape per RFC 9051 §6. LOGIN user pass takes exactly two atoms or strings. SELECT takes one mailbox name. FETCH takes a sequence-set + a parts list. Refusals under strict use guard-imap-command/bad-shape.
## Caps
- Command line (tag + verb + arguments excluding literal payload) capped at 8 KiB. RFC 9051 does not mandate a line cap but most servers limit at 8 KiB or 16 KiB to bound memory; operators on permissive can extend. - Mailbox name capped at 1 KiB. - Sequence set element count capped at 10,000 per command. - SEARCH expression nesting (AND/OR/NOT) capped at 32 levels. - Per-literal byte cap (64 MiB default).
Throws GuardImapCommandError on every refusal. Pure-functional — no I/O, no state. The IMAP listener composes one instance per accepted connection.
b.guardImapCommand.validate(line, opts?) #
{
profile: "strict" | "balanced" | "permissive",
posture: "hipaa" | "pci-dss" | "gdpr" | "soc2",
authenticated: boolean, // when true, LITERAL+ (RFC 7888) is honored under
strict; pre-AUTH literal+ is refused per RFC 7888 §1
}
Validate a single IMAP command line (without its CRLF terminator — the listener strips that before calling this). Returns { tag, verb, args, literalSize, literalNonSync } on success; throws GuardImapCommandError on any refusal. literalSize is the pending-literal byte count when the line ends in {n}; null otherwise. literalNonSync is true for RFC 7888 LITERAL+ ({n+}).
var parsed = b.guardImapCommand.validate("A001 LOGIN alice secret");
// → { tag: "A001", verb: "LOGIN", args: ["alice", "secret"], literalSize: null, literalNonSync: false }
var pending = b.guardImapCommand.validate("A002 APPEND INBOX {1024}");
// → { tag: "A002", verb: "APPEND", args: ["INBOX"], literalSize: 1024, literalNonSync: false }
b.guardImapCommand.detectLiteralSmuggling(line) #
Return true when the input line contains a literal opener {n} or {n+} that is NOT at the end of the line — the smuggling-shape per RFC 9051 §2.2.2.
b.guardImapCommand.detectLiteralSmuggling("A001 APPEND INBOX {10} hostile"); // → true
b.guardImapCommand.detectLiteralSmuggling("A001 APPEND INBOX {10}"); // → false (well-formed)
b.guardImapCommand.compliancePosture(name) #
Return the effective profile NAME for a compliance posture, or null for a name this parser does not map. Unlike the content-guard variant this returns the resolved profile string (every line-protocol parser composes gateContract.ALL_STRICT_POSTURES, so "hipaa" / "pci-dss" / "gdpr" / "soc2" all resolve to "strict") and never throws — the parser shape carries no overlay-clone, no buildProfile, and no loadRulePack. Wired by gateContract.defineParser.
b.guardImapCommand.compliancePosture("hipaa"); // → "strict"
b.guardImapCommand.compliancePosture("not-a-regime"); // → null
Last updated 2026-08-08T16:39:49.652Z by seeder.