ipaddress.ip_address() Rejects Leading Zeros, socket.inet_aton() Silently Treats Them as Octal (tested)

If an IPv4 octet has a leading zero, is 010 the number ten, or the octal value eight? We measured Python's two different IPv4 parsers on exactly this input, and they disagree: one silently interprets it as octal, the other refuses to guess and raises an error instead.

1. socket.inet_aton() silently reads leading-zero octets as octal

import socket

for s in ["0177.0.0.1", "010.0.0.1", "192.168.01.1"]:
    b = socket.inet_aton(s)
    print(s, "->", ".".join(str(x) for x in b))
0177.0.0.1 -> 127.0.0.1
010.0.0.1 -> 8.0.0.1
192.168.01.1 -> 192.168.1.1

Measured: socket.inet_aton() accepts all three strings without complaint. 0177 becomes 127 (octal 177 = decimal 127), 010 becomes 8 (octal 10 = decimal 8), and 01 becomes 1. It's quietly applying C's classic octal-if-leading-zero numeric parsing rule to each octet -- the same rule int("010", 0) would apply, not the rule most people assume for a dotted-quad string.

2. ipaddress.ip_address() rejects every one of the same strings

import ipaddress

for s in ["0177.0.0.1", "010.0.0.1", "192.168.01.1"]:
    try:
        print(s, "->", ipaddress.ip_address(s))
    except ValueError as e:
        print(s, "-> REJECTED:", e)
0177.0.0.1 -> REJECTED: '0177.0.0.1' does not appear to be an IPv4 or IPv6 address
010.0.0.1 -> REJECTED: '010.0.0.1' does not appear to be an IPv4 or IPv6 address
192.168.01.1 -> REJECTED: '192.168.01.1' does not appear to be an IPv4 or IPv6 address

Measured: the modern ipaddress module refuses all three inputs outright -- it treats a leading zero in any octet as invalid rather than guessing at octal-vs-decimal. Ordinary addresses with no leading zeros, like 127.0.0.1, parse identically and successfully in both modules; the disagreement only shows up on this specific, easy-to-miss input shape.

3. Why this matters: two parsers, one input, two different trusted addresses

import ipaddress, socket

candidate = "0177.0.0.1"
try:
    ipaddress.ip_address(candidate)
    allowed = True
except ValueError:
    allowed = False
print("ipaddress says valid:", allowed)
print("socket.inet_aton resolves it to:", ".".join(str(x) for x in socket.inet_aton(candidate)))
ipaddress says valid: False
socket.inet_aton resolves it to: 127.0.0.1

Measured: if one part of a codebase validates or blocklists an IP string with ipaddress (which correctly rejects "0177.0.0.1") while another part actually connects or compares using socket.inet_aton() or C-level address parsing (which silently resolves the same string to 127.0.0.1, i.e. localhost), the two parts disagree about what address the string means. This exact ambiguity -- the same dotted-quad string meaning two different IPs depending on which parser reads it -- is a known class of IP-validation bypass bug, which is why ipaddress deliberately refuses to parse leading zeros at all rather than picking one interpretation. If you're validating untrusted IP strings, use ipaddress everywhere in that path, not socket.inet_aton() or manual splitting.

Frequently asked questions

Does Python's ipaddress module accept IPv4 octets with leading zeros?

No -- we measured ipaddress.ip_address() raising ValueError on every leading-zero octet we tried (e.g. '010.0.0.1', '0177.0.0.1'), even though each octet is a normally-valid number once the leading zero is removed.

Does socket.inet_aton() accept leading zeros in IPv4 addresses?

Yes, and it interprets them as octal -- we measured socket.inet_aton('0177.0.0.1') returning 127.0.0.1, since octal 177 equals decimal 127, not the digits read literally as decimal.

Why does '010.0.0.1' mean two different things in Python?

Because socket.inet_aton() parses leading-zero octets as octal (010 octal = 8 decimal), while ipaddress.ip_address() rejects the string entirely rather than guess. We measured both behaviors on the identical input string.

Is parsing leading-zero IP addresses a security risk?

It can be -- we measured that two stdlib functions disagree on what a leading-zero address string resolves to. If one part of a system validates with one parser and another part connects with the other, an attacker-supplied address string can mean different things to each, which is a known IP-validation bypass pattern.

Which Python function should I use to validate untrusted IP address strings?

ipaddress.ip_address() (or ip_network()) -- we measured it being the stricter of the two, rejecting ambiguous leading-zero input that socket.inet_aton() silently accepts and reinterprets as octal.

Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in ipaddress and socket modules: parsed IPv4 strings with a leading zero in one octet (e.g. '0177.0.0.1', '010.0.0.1', '192.168.01.1') with both ipaddress.ip_address() and socket.inet_aton(), and compared the results. PlainHeaders is our extension; Python's ipaddress and socket modules are built in.