VNX-350: Reliance on Reverse DNS Resolution for a Security-Critical Action
An access decision made on the host name a reverse DNS lookup returned for the peer's address, without forward confirmation, in Python, Java, Go, JavaScript/TypeScript, PHP and Ruby.
| Field | Value |
|---|---|
| Rule ID | VNX-350 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Go, Java, JavaScript / TypeScript, PHP, Python, Ruby |
| CWE | CWE-350 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | host-validation cwe-350 |
| Source | internal/sast/rules/vnx-350.rego |
Overview
VNX-350 maps to CWE-350: Reliance on Reverse DNS Resolution for a Security-Critical Action. It reports a reverse DNS lookup whose result is compared, on the same line or within the next eight lines, to decide something:
- Python
socket.gethostbyaddr()/getnameinfo(),socket.getfqdn(address)(not the argument-less local form), dnspythonresolve_address(); - Java
request.getRemoteHost(),InetAddress.getCanonicalHostName()/getHostName(); - Go
net.LookupAddr(); Nodedns.reverse()/dns.promises.reverse(); - PHP
gethostbyaddr()and$_SERVER['REMOTE_HOST']; RubyResolv.getname().
The comparison may be on the name directly, a loop variable over the names or a callback parameter: endsWith, HasSuffix, equals, ==, in, includes, preg_match, =~.
Why This Matters
The PTR record for an address is published by whoever controls that address block. An attacker sets the PTR for their own IP to gw.example.com and passes any suffix or allowlist check on the name.
Not reported: forward-confirmed lookups (the name resolved again with gethostbyname, getaddrinfo, LookupHost, getAllByName or dns.lookup within the window, as done to verify Googlebot), names that are only logged or displayed, null and empty checks, the local host name (getLocalHost()), comments and string literals.
What Gets Flagged
host = socket.gethostbyaddr(request.remote_addr)[0]
if host.endswith(".corp.example.com"):
return True
if (request.getRemoteHost().endsWith(".internal.example.com")) {
names, err := net.LookupAddr(ip)
// ...
for _, n := range names {
if strings.HasSuffix(n, ".example.com.") {
Remediation
- Decide on the peer’s address (an IP allowlist or network range), or on authentication, not on its name.
- If a name is required, forward-confirm it: resolve the name returned by the reverse lookup and accept it only when the peer’s address is among the results.
References
- CWE-350: Reliance on Reverse DNS Resolution for a Security-Critical Action
- Google: Verifying Googlebot
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-350
// nosec vnx-350
Or record an ignore rule: vulnetix ignore add --rule vnx-350 --reason "...". See Suppressing findings.