Skip to content

net: parsePort accepts oversized decimal ports after integer overflow #80168

Description

@M0nd0R

Go version

Tested with current master and reported against Go 1.26.3 / Go 1.27 development builds.

What did you do?

net.parsePort accumulates decimal digits in a uint32. For oversized decimal port strings, multiplication can overflow before the current cutoff check clamps the value.

A small reproducer:

package main

import (
	"fmt"
	"net"
)

func main() {
	addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:4294985376")
	fmt.Printf("addr=%v err=%v\n", addr, err)
}

4294985376 is 2^32 + 18080.

What did you expect to see?

The oversized port should be rejected as invalid, the same way other ports outside the valid TCP/UDP range are rejected.

What did you see instead?

The port wraps during parsing and is accepted as port 18080.

The issue appears to come from src/net/port.go. The parser currently clamps when n >= 1<<30, but uint32 multiplication by 10 overflows when n > math.MaxUint32/10. For example:

n = 429498537
n *= 10 // wraps from 4294985370 to 18074 as uint32
nn = 18074 + 6 // 18080, no addition overflow

The final LookupPort range check then accepts the wrapped value because 18080 is in range.

Why this matters

This creates a parser differential between URL-level validation and dial-level behavior. For example, net/url leaves an oversized numeric port string visible via URL.Port(), while a later net.Dial / http.Client path can resolve and connect to the wrapped low port. Applications that denylist sensitive ports based on URL.Port() but then fetch the original URL can miss the actual port that will be dialed.

This is not a vulnerability in every Go program, and applications that strictly reject ports outside [1, 65535] or reconstruct URLs from validated components are not affected. It is still a real parsing bug and can bypass denylist-based SSRF protections in affected applications.

Possible fix

Clamp before multiplication can overflow, for example by checking n > max/10 before n *= 10, or by otherwise parsing in a way that rejects/clamps oversized decimal ports before wraparound occurs.

A related hardening option is for net/url.validOptionalPort to reject numeric port strings outside [0, 65535], but the concrete wraparound bug is in net.parsePort.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions