CWE-348, Use of Less Trusted Source, covers a product that has two sources for the same information and uses the one with less support for verification, less trust, or less resistance to attack.
Web developers meet it most often with client IP addresses, but the idea applies to any value that can come from more than one place.
How it happens
Information often arrives twice. The network connection tells you the peer address. A request header also claims one. The header is easier to read in some frameworks, so code reaches for it. The header, though, is written by whoever sent the request.
MITRE's observed examples are all this pattern. CVE-2001-0860 describes a product that used an IP address provided by the client instead of getting it from packet headers, which made spoofing easier. CVE-2004-1950 describes a web product using the IP address in the X-Forwarded-For HTTP header instead of a server variable holding the connecting address. CVE-2001-0908 logs the client specified IP address, which lets an attacker hide their identity.
What an attacker gains
MITRE lists bypass of protection mechanisms and gaining privileges or assuming identity. If an allowlist, rate limit or audit log keys on the weaker source, the attacker simply writes the value they want. They can look like an internal address, dodge a block, or leave a false trail.
How to find it
The record lists no detection methods. A review is quick and effective.
- Search for reads of headers such as X-Forwarded-For or any client supplied address field.
- For each hit, ask what stronger source exists for the same fact, and why it is not used.
- Check what the value controls: access decisions, rate limits, logs.
How to fix it
MITRE has no mitigation list for this entry. The fix follows from the definition: use the source that is harder to forge.
A vulnerable pattern in Python:
# Vulnerable: the client controls this header
ip = request.headers.get("X-Forwarded-For", request.remote_addr)
if ip in ADMIN_NETWORK:
allow()
A safer pattern uses the connection address, and only honors a forwarding header when it comes from a proxy you run:
TRUSTED_PROXIES = {"10.0.0.5"}
def client_ip(request):
peer = request.remote_addr
if peer in TRUSTED_PROXIES:
forwarded = request.headers.get("X-Forwarded-For", "")
if forwarded:
return forwarded.split(",")[-1].strip()
return peer
Taking the last entry matters. Each proxy appends the address it saw, so the final entry added by your trusted proxy is the one you can rely on. Entries further left may have been written by the client.
Beyond the code, an IP address is a weak basis for access decisions. Use real authentication for anything sensitive.
Quick check
Why is X-Forwarded-For risky to trust on its own?
Any client can send the header with any value. Unless a proxy you control sets it, the value is attacker supplied, as in CVE-2004-1950.
What is the general rule behind this weakness?
When the same data is available from two sources, use the one that is harder to forge and can be verified.
Sources
- MITRE CWE-348: https://cwe.mitre.org/data/definitions/348.html