Impact
@fastify/forwarded resolves client addresses from the X-Forwarded-For header. When the header contains two or more comma-separated entries, the parser trims only space characters and does not strip horizontal tabs (\t), even though RFC 7230 defines optional whitespace as both space and tab. As a result, a tab-padded entry keeps the literal tab in the resolved address string.
For example, X-Forwarded-For: 9.9.9.9,\t1.2.3.4 resolves to "\t1.2.3.4" instead of "1.2.3.4".
This affects applications that make exact-string-match security decisions on the resolved client IP (an allowlist, a blocklist, a per-IP rate-limit key, or audit-log correlation), typically via @fastify/proxy-addr and Fastify's request.ip. By adding a tab before their own address, an attacker makes the resolved string no longer match the expected value, silently evading the check. The flaw does not cross the trust boundary, since a tab-corrupted string is not a valid IP and cannot be mistaken for a trusted proxy.
Patches
This vulnerability has been patched in @fastify/forwarded 3.0.2. All users should upgrade to this version or later.
Workarounds
If upgrading is not immediately possible, normalize the resolved address before any exact-match comparison (for example ip.replace(/[\t ]/g, '')), or reject requests whose X-Forwarded-For header contains a tab with an onRequest hook:
fastify.addHook('onRequest', async (request, reply) => {
const xff = request.headers['x-forwarded-for']
if (xff && xff.includes('\t')) {
reply.code(400).send({ error: 'Invalid X-Forwarded-For header' })
}
})
References
Impact
@fastify/forwardedresolves client addresses from theX-Forwarded-Forheader. When the header contains two or more comma-separated entries, the parser trims only space characters and does not strip horizontal tabs (\t), even though RFC 7230 defines optional whitespace as both space and tab. As a result, a tab-padded entry keeps the literal tab in the resolved address string.For example,
X-Forwarded-For: 9.9.9.9,\t1.2.3.4resolves to"\t1.2.3.4"instead of"1.2.3.4".This affects applications that make exact-string-match security decisions on the resolved client IP (an allowlist, a blocklist, a per-IP rate-limit key, or audit-log correlation), typically via
@fastify/proxy-addrand Fastify'srequest.ip. By adding a tab before their own address, an attacker makes the resolved string no longer match the expected value, silently evading the check. The flaw does not cross the trust boundary, since a tab-corrupted string is not a valid IP and cannot be mistaken for a trusted proxy.Patches
This vulnerability has been patched in
@fastify/forwarded3.0.2. All users should upgrade to this version or later.Workarounds
If upgrading is not immediately possible, normalize the resolved address before any exact-match comparison (for example
ip.replace(/[\t ]/g, '')), or reject requests whoseX-Forwarded-Forheader contains a tab with anonRequesthook:References