postal-mime: Quadratic CPU consumption when decoding a header of many joinable RFC 2047 base64 encoded words
GHSA-f2hq-32vh-53cc · published 23 Oct 2026
How serious is it
- Severity: high, CVSS score 7.5 out of 10.
- No exploit prediction (EPSS) score yet.
- Not on the CISA list of exploited vulnerabilities.
- No public exploit in Exploit-DB.
Is your app affected by GHSA-f2hq-32vh-53cc?
Paste this prompt into Claude Code, Cursor or any AI coding tool: it runs a free Shippable scan of your project and fixes what it finds. Built with Lovable, Bolt or v0? Scan your live app. Or upload your package file.
Who is affected
postal-mime(npm) >= 3.0.0, < 4.0.8
How to check
- Run
npm ls postal-mimein your project to see the installed version, including copies pulled in by other packages. - Or paste your lockfile into the checker: it lists every package with a known vulnerability, this one included.
- Or run
npx shippable-dev scan localhost:3000in your project folder. It reads your lockfile and flags this vulnerability along with every other known one.
How to fix
Copies a prompt for Claude Code, Cursor or Codex: it checks your lockfiles for this and upgrades it.
- Upgrade
postal-mimeto 4.0.8 or later, commit the lockfile and redeploy. - If a vulnerable version was live, check your logs and rotate the secrets that server could read.
The advisory
### Impact
Decoding a header that holds a long run of joinable RFC 2047 base64 encoded words, such as `=?utf-8?B?QUJD?=` repeated tens of thousands of times in a `Subject`, `From`, `To`, a filename or a description, took time quadratic in the number of words. The join check ran a regex over the text joined so far for every word, which flattens the accumulated string each time. A single well formed message of about 1.6 MB blocked the event loop for one to twenty seconds depending on the host, and inline `message/rfc822` parts multiplied the cost, since each nested message carried its own header budget.
Any application that parses untrusted mail with postal-mime 3.0.0 through 4.0.7, including the exported `decodeWords()` helper, is affected. There is no confidentiality or integrity impact.
### Patches
Fixed in 4.0.8. The pad check now tracks the last appended word instead of testing the joined text, so decoding is linear in the header length. The same release also counts the parts and header bytes of inline `message/rfc822` sub-messages against the limits of the message as a whole, counts every header line for at least 64 bytes of `maxHeadersSize`, and adds a scaling test that measures every stage of the parser at two input sizes.
### Workarounds
Lower `maxHeadersSize` from its 2 MiB default to bound the cost per message, or parse untrusted mail in a worker that can be terminated.
### Credits
Reported by Felipe Fernández.
Check your whole app
Dependencies are only half of it. Free and read-only: before you push, run npx shippable-dev scan localhost:3000 in your project folder, no account needed. For your live app, you prove it's yours with a one-line tag first.
References
- github.com/postalsys/postal-mime/security/advisories/GHSA-f2hq-32vh-53cc
- github.com/postalsys/postal-mime/commit/9eb25a66bb3cc8b631421be651b9648796f19136
- github.com/postalsys/postal-mime/releases/tag/v4.0.8
- github.com/advisories/GHSA-f2hq-32vh-53cc
- github.com/postalsys/postal-mime
Merged from GitHub Advisory Database, OSV. Last updated 26 Oct 2026. All vulnerabilities · RSS · JSON