Safeguard
Supply Chain Security•

NAT64, DNS64 and 464XLAT Explained: IPv6-Only Networks and Security

NAT64 translates IPv6 to IPv4, DNS64 fakes AAAA records and 464XLAT rescues IPv4 literals. How each works, where it breaks and how to secure it.

Safeguard Security Team
52 min read

An IPv6-only network reaches the IPv4 internet through three cooperating pieces. Stateful NAT64 (RFC 6146) translates IPv6 packets into IPv4 packets and back, DNS64 (RFC 6147) invents AAAA records that point IPv6 clients at the translator, and 464XLAT (RFC 6877) adds a small translator on the client so that software which insists on IPv4 still works. To secure the result you must restrict who can use the translator, log its address and port mappings, protect the router advertisements and DHCP that carry its configuration, and stop assuming that IPv4 firewall rules still describe who is talking to whom.

This post goes one level deeper than our comparison of IPv4 and IPv6, our guide to SLAAC, DHCPv6 and privacy addresses and our explainer on what NAT does and does not secure. It walks through the address formats with worked numbers, the DNS64 and DNSSEC conflict, prefix discovery through ipv4only.arpa and the PREF64 router advertisement option, the DHCPv4 option that lets mixed networks turn IPv4 off per device, the security problems each piece introduces, and a Linux lab that builds a NAT64, a DNS64 resolver and a client side translator from open source parts.

Key takeaways

  • NAT64 is stateful translation between IPv6 clients and IPv4 servers. RFC 6146 (April 2011) requires Endpoint-Independent Mapping and keeps three binding tables (TCP, UDP and ICMP queries). Only IPv6 side traffic creates state.
  • IPv4 addresses are embedded in IPv6 addresses using RFC 6052 (October 2010). The Well-Known Prefix is 64:ff9b::/96, so 192.0.2.33 becomes 64:ff9b::c000:221. RFC 8215 (August 2017) reserved 64:ff9b:1::/48 for local use inside a single network.
  • RFC 6052 forbids combining the Well-Known Prefix with private or other non-global IPv4 addresses. Other prefixes carry no such rule, so you must write that filtering yourself.
  • DNS64 synthesises AAAA records from A records when a name has no real AAAA. That conflicts with DNSSEC validation on the client and is invisible to clients using their own encrypted DNS resolver.
  • Clients learn the translation prefix by asking for the AAAA record of ipv4only.arpa (RFC 7050, November 2013; made a special use name by RFC 8880, August 2020) or from the PREF64 option in router advertisements (RFC 8781, April 2020). RFC 9872 (September 2025) tells endpoints and operators to prefer PREF64.
  • 464XLAT pairs a stateless customer side translator (CLAT) with a stateful provider side translator (PLAT). The CLAT gives applications a private IPv4 address and default route, which rescues IPv4 literals and IPv4-only socket code.
  • DHCPv4 option 108 (RFC 8925, October 2020) lets an IPv6-only capable device switch IPv4 off for a while when the server says so. The default wait is 1800 seconds, the minimum 300.
  • The security work is operational: limit who can use the NAT64, keep timestamped mapping logs, guard router advertisements and DHCP, block translation into internal ranges, and audit ACLs written for IPv4.

Why operators run IPv6-only networks, and which transition mechanisms exist

The plain reason is that public IPv4 addresses ran out. RFC 6877 opens by noting that with the exhaustion of the unallocated IPv4 address pools it will be difficult for many networks to assign IPv4 addresses to end users, and the DS-Lite specification (RFC 6333, August 2011) is titled after the problem it solves: broadband deployments following IPv4 exhaustion.

Dual stack does not remove the need for IPv4 addresses: every dual stack subscriber or server still needs one, usually shared behind carrier grade NAT, and the operator runs two address plans, two sets of ACLs and two monitoring pipelines. An IPv6-only network removes one stack from the inside and pushes IPv4 to a few translation or encapsulation points at the edge.

Three types of network moved first:

  • Mobile carriers. RFC 6877's main scenario is a phone performing the CLAT function on an IPv6-only mobile core with a PLAT at the edge. RFC 8683 (November 2019) extends the guidance to broadband and enterprise networks.
  • Data centres and cloud networks. Workloads that talk over IPv6 need no IPv4, and one NAT64 handles the few calls to IPv4-only services.
  • Enterprise and campus networks. RFC 8925 describes "IPv6-mostly" segments where IPv6-only capable and legacy dual stack devices share a network, so IPv4 retires one device class at a time.

The transition mechanisms in one list

RFC 9313 (October 2022) compares the five most prominent "IPv4 as a service" technologies an IPv6-only operator can choose from. Together with NAT64 itself they form the menu:

MechanismSpecificationWhat it does
Stateful NAT64 with DNS64RFC 6146, RFC 6147Translates IPv6 client packets to IPv4 at one stateful box; DNS64 points clients at it
464XLATRFC 6877Stateless CLAT on the client side plus stateful NAT64 (the PLAT) at the provider
DS-LiteRFC 6333Client router (B4) tunnels IPv4 inside IPv6 to a carrier NAT (the AFTR) that holds all state
Lightweight 4over6RFC 7596Like DS-Lite, but the client router does its own NAT into an assigned port range
MAP-ERFC 7597Stateless mapping of address and port, with IPv4 encapsulated in IPv6
MAP-TRFC 7599Stateless mapping of address and port, with IPv4 translated into IPv6

The difference that matters most for security is where the state lives. In NAT64, 464XLAT and DS-Lite, the operator's translator or AFTR knows which internal endpoint used which public IPv4 address and port at each moment, so that box is where attribution logs come from. In MAP-E, MAP-T and lightweight 4over6, each customer router owns a fixed slice of a shared IPv4 address's port range, so attribution comes from the provisioning records that map port sets to subscribers.

A dated timeline of the standards

DateDocumentWhat it added
October 2010RFC 6052IPv6 address formats for translators; the Well-Known Prefix 64:ff9b::/96
April 2011RFC 6146Stateful NAT64: binding tables, session tables, timers, filtering
April 2011RFC 6147DNS64: AAAA synthesis, exclusion rules, PTR handling, DNSSEC cases
August 2011RFC 6333DS-Lite, with B4 and AFTR elements and the 192.0.0.0/29 range
April 2013RFC 6877464XLAT: CLAT plus PLAT
April 2013RFC 6888Common requirements for carrier grade NATs, including logging (REQ-12)
April 2013RFC 6889Analysis of stateful 64 translation
November 2013RFC 7050Prefix discovery through the AAAA record of ipv4only.arpa
November 2013RFC 7051Analysis of the competing prefix discovery proposals
May 2014RFC 7225Learning NAT64 prefixes through the Port Control Protocol
June 2014RFC 7269NAT64 deployment options and experience
July 2015RFC 7597, RFC 7599MAP-E and MAP-T
June 1, 2016Apple App Store ruleAll new app submissions must support IPv6-only networks
August 2017RFC 8215Local-use translation prefix 64:ff9b:1::/48
November 2019RFC 8683Further NAT64 and 464XLAT deployment guidelines for operators and enterprises
April 2020RFC 8781PREF64 option in router advertisements
August 2020RFC 8880ipv4only.arpa registered as a special use domain name
October 2020RFC 8925IPv6-Only Preferred option (code 108) for DHCPv4
October 2022RFC 9313Pros and cons of the five IPv4 as a service technologies
September 2025RFC 9872Recommends PREF64 over the DNS heuristic for prefix discovery
January 26, 2026Jool 4.1.15Latest release of the open source Linux SIIT and NAT64 used in the lab below

How stateful NAT64 works

A stateful NAT64 sits between an IPv6 network and an IPv4 network. It owns a translation prefix on the IPv6 side (written Pref64::/n) and a pool of IPv4 transport addresses on the IPv4 side. When an IPv6 client sends a packet to Pref64:: followed by an IPv4 address, the router delivers it to the NAT64, which:

  1. Extracts the destination IPv4 address from the low bits of the IPv6 destination address.
  2. Looks up or creates a binding that maps the client's IPv6 address and port to an IPv4 address and port from its pool.
  3. Creates or refreshes a session entry for the flow.
  4. Rewrites the IP header from IPv6 to IPv4, recalculates the transport checksum and forwards the packet.

Replies arrive at the pool address and port, match the binding and session, and are translated back in the other direction. The IPv4 server never sees an IPv6 address. It sees a connection from the NAT64's pool.

Binding tables and session tables

RFC 6146 keeps two kinds of state. The Binding Information Base (BIB) holds mappings from an IPv6 transport address to an IPv4 transport address. A NAT64 has one BIB for TCP, one for UDP and one for ICMP queries, because the TCP and UDP port spaces are separate. The session tables hold each individual flow, including the remote IPv4 endpoint, and they are what the timers act on. Dynamically created BIB entries disappear when the last session using them is removed; the RFC says implementations should also support manually configured entries, which is how you publish an IPv6-only server to IPv4 clients.

The default timers in RFC 6146 come from the earlier NAT behaviour RFCs:

TimerValueMeaning
UDP_MIN2 minutesMinimum UDP session lifetime
UDP_DEFAULT5 minutesDefault UDP session lifetime
TCP_TRANS4 minutesLifetime of a TCP session that is opening or closing
TCP_EST2 hoursMinimum lifetime of an established TCP session
TCP_INCOMING_SYN6 secondsHow long an unsolicited IPv4 SYN is held
ICMP_DEFAULT60 secondsICMP query session lifetime

The Jool documentation shows the same numbers as defaults: its udp-timeout defaults to 5:00 and its tcp-est-timeout to 2:00:00.

Mapping and filtering

RFC 6146 requires Endpoint-Independent Mapping: once a client's IPv6 address and port are mapped to an IPv4 address and port, every new flow from that same IPv6 address and port uses the same IPv4 address and port, whatever the destination. It allows both Endpoint-Independent Filtering, where any IPv4 host can send packets to an existing binding, and Address-Dependent Filtering, where only IPv4 addresses the client has already contacted can.

The RFC is explicit that security comes from filtering, not from mapping. With Endpoint-Independent Mapping and no filtering, packets from any IPv4 node to an existing binding are forwarded to the IPv6 client that created it. Jool exposes the choice as address-dependent-filtering: on makes the translator a restricted cone NAT and off makes it a full cone NAT. Its documentation points out that turning it on can break NAT traversal methods, some games and peer to peer applications, and refers operators to RFC 6888 REQ-7, which recommends endpoint-independent filtering for carrier grade NAT.

Why NAT64 breaks some protocols

Translation changes the IP header, so anything that protects it end to end fails: RFC 6146 section 5.1 says IPsec AH and transport mode ESP fail through NAT64, and UDP encapsulation (RFC 3948) restores end to end IPsec. Protocols that carry IP addresses in their payload need application layer gateways. Software that opens an IPv4 socket to an address literal cannot use NAT64 at all, because the client has no IPv4 stack; that case is what 464XLAT exists for.

The translation prefixes: 64:ff9b::/96, Network-Specific Prefixes and 64:ff9b:1::/48

RFC 6052 defines how an IPv4 address is embedded in an IPv6 address. The prefix can be 32, 40, 48, 56, 64 or 96 bits long. Bits 64 to 71 (the "u" octet) are reserved for compatibility with the IPv6 interface identifier format and must be zero, so for prefixes shorter than /96 the IPv4 address is split around that octet. A /96 prefix puts all 32 bits of IPv4 address at the end, which is why 64:ff9b::/96 addresses are easy to read.

Worked example 1: the Well-Known Prefix

Take the IPv4 address 192.0.2.33. In hexadecimal its four octets are c0, 00, 02 and 21. With the /96 Well-Known Prefix the address becomes:

64:ff9b::  +  c000:0221   =   64:ff9b::c000:221

Most tools also accept and print the mixed notation 64:ff9b::192.0.2.33. The Jool tutorial shows the same thing in a live ping: ping6 64:ff9b::203.0.113.16 prints 64:ff9b::cb00:7110, because 203 is cb, 0 is 00, 113 is 71 and 16 is 10.

The two addresses that ipv4only.arpa resolves to, 192.0.0.170 and 192.0.0.171, become 64:ff9b::c000:aa and 64:ff9b::c000:ab behind a DNS64 that uses the Well-Known Prefix.

Worked example 2: a /48 Network-Specific Prefix and the u octet

Now take the RFC 6052 example prefix 2001:db8:122::/48 and the same IPv4 address. The prefix fills bits 0 to 47. The first 16 bits of the IPv4 address (c000) fill bits 48 to 63. Bits 64 to 71 are the u octet, which is zero. The remaining 16 bits of the IPv4 address (0221) fill bits 72 to 87, and the rest is zero suffix:

bits  0-47   2001:0db8:0122
bits 48-63   c000            first half of 192.0.2.33
bits 64-71   00              u octet, always zero
bits 72-87   0221            second half of 192.0.2.33
bits 88-127  zero suffix
result       2001:db8:122:c000:2:2100::

The fifth group is 0002 because it holds the zero u octet followed by 02, and the sixth group is 2100 because it holds 21 followed by the first suffix octet. This matches the table in RFC 6052. The same address under a /64 prefix of 2001:db8:122:344::/64 becomes 2001:db8:122:344:c0:2:2100::.

So unless you use a /96, you cannot match synthesised addresses with a string pattern: log parsers and SIEM queries should match the prefix and decode the embedded address with the RFC 6052 algorithm.

Rules for the Well-Known Prefix

RFC 6052 section 3.1 says the Well-Known Prefix must not be used to represent non-global IPv4 addresses, such as the RFC 1918 private ranges, and that translators must drop packets in which the Well-Known Prefix is combined with a non-global IPv4 address. That is a safety rule: it stops the public, well-known prefix from becoming a way to reach private IPv4 networks. It also says the Well-Known Prefix must not be used when the IPv6 internet needs to reach an IPv4 network; that scenario requires a Network-Specific Prefix.

The RFC gives sizing advice for operator chosen prefixes: an ISP holding a /32 should use a /40 for the translation service, and a site holding a /48 should use a /56, though a /64 or /96 is also possible.

Why RFC 8215 reserved 64:ff9b:1::/48

Seven years later, operators wanted to run several translation mechanisms at once, some of which do not use the RFC 6052 algorithm and some of which need to reach private IPv4 addresses. The Well-Known Prefix could only serve one of them and came with the non-global restriction. RFC 8215 reserves 64:ff9b:1::/48 "for local use within domains that enable IPv4/IPv6 translation mechanisms". The authors chose /48 because the shortest translation prefix reported in live use was a /64, and /48 is the longest 16 bit aligned length that can hold several /64s. They chose the value to sit next to the existing Well-Known Prefix.

For a lab or an internal deployment that must translate to private IPv4 servers, a /96 carved from 64:ff9b:1::/48 is the natural choice, and that is what the step by step section below uses. The trade off is that the restriction RFC 6052 placed on the Well-Known Prefix no longer protects you, so you must write the equivalent filters yourself.

How DNS64 synthesises AAAA records

DNS64 is a resolver feature. When an IPv6-only client asks for the AAAA record of a name, the DNS64 resolver first tries to get a real AAAA answer. If the name has AAAA records, the client gets them and talks native IPv6; no translation is needed. If the name has no AAAA records, the resolver asks for the A records and builds AAAA records by placing each IPv4 address inside the translation prefix. The client connects to the synthesised IPv6 address, and the network routes that address to the NAT64.

Several details in RFC 6147 matter in practice:

  • Exclusions. AAAA records that point into the IPv4-mapped range ::ffff:0:0/96 should be treated as excluded. If the only AAAA answers are excluded, the resolver synthesises from the A records instead.
  • TTL. The synthesised record's TTL is the minimum of the original A record's TTL and the TTL of the SOA record from the negative AAAA answer. If the A record has a TTL of 3600 seconds and the zone's SOA came back with 900, the synthesised AAAA lives for 900 seconds.
  • Reverse lookups. A PTR query in ip6.arpa for an address inside the translation prefix must be handled by stripping the labels, recovering the IPv4 address and answering from in-addr.arpa, either by synthesising a CNAME or by querying on the client's behalf.
  • Prefix agreement. The DNS64 and the NAT64 must use the same Pref64::/n. RFC 6147's security section warns that an attacker who changes the prefix used by the DNS64 can cause a denial of service, flood a third party, or eavesdrop if the altered prefix is routed through the attacker.

In Unbound, the dns64 module must be listed in module-config, for example module-config: "dns64 validator iterator". The dns64-prefix option sets the synthesis prefix, must be /96 or shorter and defaults to 64:ff9b::/96. dns64-ignore-aaaa lists domains whose real AAAA records should be ignored in favour of synthesis. dns64-synthall is marked in the manual as a debugging feature that synthesises even when real AAAA records exist. The manual also notes that if you use the respip module for response policy feeds, it must appear before dns64 in module-config so filtering applies regardless of synthesis.

In BIND, the Jool DNS64 tutorial shows a dns64 64:ff9b::/96 block inside options with a clients list that excludes the translator itself, because Jool translates only traffic that passes through it and cannot translate traffic the translator host originates.

Why DNS64 collides with DNSSEC

DNSSEC exists to detect changes to DNS answers. DNS64 changes DNS answers. RFC 6147 section 3 walks through seven combinations of the DNSSEC OK (DO) bit and the Checking Disabled (CD) bit, and the outcome is simple to state:

Client behaviourWhat happens
Not DNSSEC aware (DO clear)Works. A validating DNS64 validates the A answer, then synthesises. The client cannot tell
DNSSEC aware but trusts the resolver (DO set, CD clear)Works. A validating DNS64 validates, synthesises and sets the AD bit
Validates for itself (DO set, CD set)Fails. The synthesised AAAA has no valid signature, so the client marks it bogus

The third row is the important one for security minded hosts. A device that does its own DNSSEC validation cannot use a network DNS64. RFC 6147 says such a node must perform DNS64 itself. RFC 8880's security section describes the intended workflow: query ipv4only.arpa to learn the synthesis prefix, query for the signed A record of the real name and validate it, then synthesise the AAAA locally. RFC 8781 lists local DNSSEC validation as the first reason a host needs to know the NAT64 prefix.

Why encrypted DNS bypasses DNS64

Clients that send queries over DNS over TLS or DNS over HTTPS to a resolver of their choosing hit the same wall. That resolver does not know your translation prefix, so for an IPv4-only name it returns no AAAA records and the IPv6-only client has nowhere to connect. RFC 8781 calls this the "trusted DNS server" case: AAAA synthesis is required for a host to use a DNS server not provided by the network, and the host can only synthesise if it knows the prefix.

RFC 8880 section 3.1 describes a further failure: a device that learns the network's resolver but is configured to use another one can end up asking the wrong resolver for ipv4only.arpa, especially on multihomed hosts or with a VPN, and so learn no prefix or the wrong one.

There are two security consequences. First, if your network relies on the DNS64 resolver for policy, such as response policy zones or blocklists, a client with its own encrypted resolver and local synthesis skips that policy entirely and still reaches IPv4 destinations through the NAT64. Second, DNS is not access control for the NAT64. Any client that knows the prefix can type 64:ff9b:: followed by an IPv4 address and connect, without asking DNS anything. Policy that must hold belongs on the translator and the firewall, not only in the resolver. Our post on running your own DNS resolver covers the resolver side of that trade off.

How clients discover the prefix: ipv4only.arpa and PREF64

A host needs the prefix for local DNSSEC validation, for synthesising answers from an external resolver, for translating IPv4 literals and for running a CLAT. There are two standard ways to learn it, plus a Port Control Protocol option (RFC 7225) that is rarely seen on client devices.

The DNS heuristic: RFC 7050 and RFC 8880

RFC 7050 uses a name that is known to have only A records: ipv4only.arpa, whose two addresses are 192.0.0.170 and 192.0.0.171. The host asks its resolver for the AAAA record of that name. If the answer contains AAAA records, they must have been synthesised, so the host looks for the well-known IPv4 addresses inside them and works out the prefix and its length. The RFC says the node must check on octet boundaries, must use every prefix it learns, must set the CD bit to zero on the query, must cache the replies, and should repeat discovery ten seconds before the TTL of the answer expires.

RFC 7050 recognised the weakness: the node should use a trusted DNS64 over a secure channel or DNSSEC, but DNSSEC can only validate the operator's signed NAT64 FQDN, not whether the answer came from the network the host is attached to.

RFC 8880 (August 2020) fixed a registration gap. RFC 7050 had said the name needed no special handling, so ipv4only.arpa never entered the special use domain names registry, even though software has to treat it specially. RFC 8880 describes the lookup bluntly as DNS co-opted "as an improvised client-to-middlebox communication protocol" and formally registers the name with rules for name resolution libraries and DNS64 resolvers.

The router advertisement option: RFC 8781

RFC 8781 (April 2020) puts the prefix into the router advertisement that the host already needs for its IPv6 configuration. The option is Neighbor Discovery option type 38 and carries:

  • a 13 bit Scaled Lifetime in units of 8 seconds,
  • a 3 bit Prefix Length Code, where values 0 to 5 mean prefix lengths of 96, 64, 56, 48, 40 and 32 bits, and any other value means the option must be ignored,
  • the highest 96 bits of the prefix.

The RFC's arguments for using router advertisements are fate sharing (the NAT64 needs routing, and routing comes from the RA anyway), atomic configuration (one packet configures the whole host), updatability (a new RA can change the prefix) and deployability (every IPv6 host already processes Neighbor Discovery).

Worked example 3: the PREF64 lifetime

The sender should set the Scaled Lifetime to the lesser of three times the router's MaxRtrAdvInterval divided by 8, or 8191. Suppose your router sends unsolicited advertisements with a MaxRtrAdvInterval of 600 seconds:

3 x 600 s       = 1800 s
1800 / 8        = 225     Scaled Lifetime field value
receiver: 225 x 8 = 1800 s  prefix valid for 30 minutes

The largest value the field can hold is 8191, so the longest lifetime a PREF64 option can express is 8191 x 8 = 65528 seconds, a little over 18 hours. The RFC advises operators not to configure router lifetimes longer than 65528 seconds on networks that use the option, so the prefix does not expire while the default route is still valid.

Which method to use

RFC 9872 (September 2025) settles the question for most networks. Endpoints should try to get the prefix from router advertisements and may fall back to RFC 7050 only when no PREF64 option is present. Operators deploying NAT64 should send PREF64. The RFC lists the problems with the DNS method: dependence on the network's resolver, delay during network stack start up, slow propagation of changes, multihoming, and security. It adds that moving away from DNS64 based discovery removes the DNSSEC conflict as well. It also makes an exception for mobile networks: support for the option is "widely integrated into modern operating systems on mobile endpoints", but mobile network equipment often cannot send it yet, so the recommendation does not currently apply to mobile operators.

How 464XLAT rescues IPv4 literals

NAT64 with DNS64 works for any application that resolves a name and then connects to whatever address comes back. It fails for software that never asks DNS for an AAAA record:

  • configuration files and server responses that contain IPv4 address literals,
  • code that opens IPv4-only sockets (AF_INET) or calls IPv4-only APIs,
  • protocols that pass IPv4 addresses inside their payload,
  • devices and applications that expect an IPv4 interface address to exist.

RFC 6877 adds a second translator on the customer side. The CLAT gives the host, or the devices behind a home router, a private IPv4 address and an IPv4 default route. IPv4 packets sent to that route are translated statelessly into IPv6, using the PLAT's translation prefix for the destination, and sent across the IPv6-only network. The PLAT, which is an ordinary stateful NAT64, translates them back into IPv4 and sends them to the internet. The name comes from the path: IPv4 to IPv6 to IPv4.

Three details matter when you secure it:

  • Double translation is a fallback. RFC 6877 says networks may use DNS64 to enable single stateful translation instead of double translation where possible. Applications that resolve names keep using DNS64 and native IPv6; only the IPv4-bound traffic uses the CLAT.
  • The CLAT wants its own /64. On a home router or a phone with DHCPv6 prefix delegation, the CLAT can use a dedicated /64 for translated traffic, which keeps the CLAT stateless and lets the operator recognise and engineer 464XLAT traffic separately. Without a dedicated /64 the CLAT may have to do stateful NAT44 first.
  • Security inherits from both sides. RFC 6877's security section points to the security considerations of RFC 6146 for the PLAT and of the stateless translation specification for the CLAT, and says the CLAT may comply with the simple security recommendations for customer premises equipment (RFC 6092).

On Linux, the open source clatd project implements the CLAT component of RFC 6877 on top of the TAYGA user space translator or the nat46 kernel module. Its default CLAT IPv4 address is 192.0.0.1. To find the PLAT prefix it first asks systemd-networkd for a prefix learned from the PREF64 option, then falls back to RFC 7050 discovery through the system resolver. It enables IPv6 forwarding and sets accept_ra to 2 where it was 1, so the host still accepts router advertisements.

What Apple and Android document about IPv6-only support

Apple's developer support page for IPv6-only networks is the clearest platform statement we found. Since June 1, 2016, apps submitted to the App Store must support IPv6-only networks. The page says NSURLSession and CFNetwork already support IPv6, and that apps using IPv4-specific APIs or hardcoded IP addresses must change. Since iOS 9.2 and OS X 10.11.2, getaddrinfo can synthesise an IPv6 address from an IPv4 address, and the page warns that combining an IPv4 address with 64:ff9b::/96 yourself "may work in some NAT64 networks" but is not a general solution. It recommends address family agnostic APIs and testing on IPv6-only Wi-Fi with cellular data off, and for local accessories it recommends IPv6 or IPv4 link-local addressing.

For Android, we could not retrieve an Android developer or Android Open Source Project page that documents the platform's 464XLAT or PREF64 behaviour while preparing this post, so we do not describe it here. RFC 9872's statement that PREF64 support is widely integrated in modern mobile operating systems is the only claim we make, and it comes from the IETF, not from the vendor. Check the Android documentation for the API levels you target before relying on a specific behaviour.

The developer lesson holds on every platform: use the system resolver and address family agnostic APIs, and never build a synthesised address by hand.

What DHCPv4 option 108 does for mixed networks

A host joining a network does not know whether it is IPv4-only, dual stack or IPv6-only, so it configures both protocols at once. RFC 8925 explains why simple fixes fail: switching IPv4 off breaks capable hosts on IPv4-only networks, delaying IPv4 penalises everyone else, and releasing an address later disrupts applications already using it.

The IPv6-Only Preferred option solves this inside DHCPv4. A client that can operate on IPv6 alone puts option code 108 in the Parameter Request List of its DHCPDISCOVER and DHCPREQUEST. If the server's pool is marked as IPv6-mostly, it returns the option with a 4 byte value: the number of seconds the client should stop DHCPv4. The client then skips IPv4 configuration for that period, or until it moves to a new network, and relies on IPv6 with NAT64 and DNS64. Devices that do not ask for the option, such as printers and older systems, get an IPv4 lease as usual. The server must not send the option to a client that did not request it.

The constants are:

VariableValue
V6ONLY_WAIT default1800 seconds
MIN_V6ONLY_WAIT300 seconds
Option value 0Sent when the pool has no configured wait; because 0 is below the minimum, the client waits 300 seconds

The client should use the larger of the server's value and MIN_V6ONLY_WAIT. A server value of 60 seconds therefore produces a 300 second pause, and a value of 7200 produces a two hour pause.

RFC 8925's security section notes that a rogue DHCP server could send the option with a value of 0xffffffff and switch IPv4 off on supporting clients, cutting them off on an IPv4-only network. A rogue server can already do worse to every client with a bad address and a huge lease time, so existing rogue DHCP defences cover this too. The RFC also calls switching IPv4 off a security feature, since it shrinks the host's attack surface.

The security issues, one by one

Translation does not create new classes of attack so much as move old ones into new places. Each of the problems below has a concrete control.

Attribution and logging for translated flows

After NAT64, every IPv6 client appears on the IPv4 internet as one of a handful of pool addresses. If an IPv4 service reports abuse from 192.0.2.2 port 8208 at 16:13 UTC, you can only answer "who was that" if you logged the binding. RFC 6888 section 4 discusses logging for carrier grade NATs, and REQ-12 says a CGN should not log destination addresses or ports unless required, because destination logs create privacy problems.

Jool implements this as two switches. logging-bib logs each mapping as it is created and destroyed, with a GMT timestamp, both transport addresses and the protocol; logging-session adds the remote endpoint. The Jool documentation says REQ-12 compliance means logging-bib on and logging-session off, notes the messages go to the kernel log at INFO priority, and flags three traps: mappings are unique per protocol, clients share IPv4 addresses so you must match on port, and times are in GMT.

The controls that make these logs usable:

  • Synchronise the translator's clock and record the time zone. A mapping log with skewed time is worthless as evidence.
  • Ship the kernel log to central storage with a retention period that matches your legal and policy requirements.
  • Log the IPv6 side of the mapping with enough context to find the device: router advertisement and DHCPv6 logs, neighbor tables or switch port data. Our post on ARP and IPv6 Neighbor Discovery covers why neighbor data needs protecting too.
  • For MAP-E, MAP-T and lightweight 4over6, keep the provisioning records that map each port set to a subscriber, since there is no per flow log.

ACLs that assume IPv4

IPv4-shaped policy breaks in both directions when you add translation.

Outbound, an IPv4 server behind a NAT64 sees every IPv6 client as the translator's pool address. If that pool address falls inside a range your IPv4 services treat as trusted, such as an internal management network or an allowlisted partner range, every IPv6 client that can reach the NAT64 inherits that trust. Give the NAT64 pool addresses of their own and grant them nothing by default.

Inbound, rules written as IPv4 prefixes do not match IPv6 clients. A rule that allows 10.20.0.0/16 to reach a database does not cover the IPv6-only clients that replaced those hosts, and the quick fix of allowing the whole translation prefix allows every client that can reach the NAT64. Rewrite rules in terms of the IPv6 client prefixes, and audit any IPv4 allowlist that contains a NAT64 pool address.

The same applies to application logic. Rate limits, geolocation, fraud scoring and audit trails keyed on the client IPv4 address will see one address for thousands of users. Our NAT explainer covers why the shared address was never an identity in the first place.

Translation into internal and metadata ranges

The Well-Known Prefix comes with a built in rule: translators must drop packets that combine it with a non-global IPv4 address. Network-Specific Prefixes and the local-use prefix do not. If your NAT64 uses one of those, a client can reach any IPv4 address the translator can route to, including private management networks, loopback ranges and the link-local range 169.254.0.0/16 that many cloud platforms use for instance metadata services. Write explicit deny rules for those embedded ranges on the IPv6 side, before translation, and allow only the internal IPv4 destinations you mean to expose.

DNS64 bypass by encrypted DNS

As described above, clients with their own resolvers lose synthesis, and clients that synthesise locally or type addresses directly skip DNS policy. Enforce destination policy on the translator or the firewall behind it.

Rogue router advertisements with a fake PREF64

If a host learns its NAT64 prefix from router advertisements, anyone who can send router advertisements on the link can give it a different prefix. All of that host's IPv4-bound traffic, from DNS64 answers synthesised locally and from the CLAT, then goes to an address range the attacker chose. RFC 8781 says that on IPv6-only networks router advertisements must already be secured, for example with RA-Guard (RFC 6105), because a rogue RA can already cause denial of service or man in the middle attacks; RFC 6147 describes the same three outcomes (denial of service, flooding, eavesdropping) for an altered DNS64 prefix. The point is that PREF64 adds no new trust: it rides on a channel that must be protected anyway. If your access switches do not filter router advertisements from host ports, fix that before you deploy NAT64.

The DNS heuristic has the matching weakness. A host using RFC 7050 believes whatever its resolver says about ipv4only.arpa. Rogue DHCP or DHCPv6 that hands out an attacker's resolver gives the attacker the prefix too. Guard DHCP on access ports for the same reason.

Open NAT64 relays

A NAT64 that accepts IPv6 packets from any source becomes a free IPv4 egress for anyone on the IPv6 internet who knows the prefix. Their scans, spam and attacks leave from your IPv4 pool addresses, and the abuse reports arrive at your door. Restrict the translator to your own client prefixes, both with routing (do not advertise the translation prefix outside the domain that should use it) and with explicit source filters on the translator.

Resource exhaustion

RFC 6146 section 5.3 lists the denial of service risks. An attacker on the IPv6 side can consume all IPv4 transport addresses by sending from many different IPv6 source addresses and ports. Fragments held for reassembly can exhaust memory. SYN floods from either side fill session tables, and IPv4 SYNs are worse because the NAT64 must hold them. Attackers can also keep a binding alive by refreshing it. The RFC requires implementations to protect against these, for example by limiting fragment memory, and allows a NAT64 not to extend session lifetimes for packets arriving on the external interface.

Simple capacity arithmetic helps size the pool. If you exclude the well-known ports and use ports 1024 to 65535, each IPv4 address offers 64,512 ports per protocol. Four pool addresses give 4 x 64,512 = 258,048 simultaneous TCP mappings. If a busy client uses 200 concurrent connections, that pool supports about 1,290 such clients before exhaustion, and a single misbehaving client can use far more. Per client port limits, or the per user pool approach the Jool pool4 documentation describes, keep one client from taking everyone's ports.

Hairpinning and loops

Hairpinning is when a packet enters a NAT and comes straight back out towards the same side, for example when two IPv6 clients talk to each other through their IPv4 representations. RFC 6146 section 5.4 describes a loop risk: an IPv6 client that can guess the IPv4 binding address it will be given can use the IPv6 representation of that address as its source, after which packets sent to the binding could loop inside the NAT64. The fix in the RFC is to filter incoming packets whose source address is inside Pref64::/n. Make sure your edge and translator filters drop IPv6 packets sourced from the translation prefix.

Hairpinned traffic also never crosses your IPv4 boundary, so IPv4 side monitoring and firewalls do not see it. If two internal clients talk through the NAT64, any inspection must happen on the IPv6 side or on the translator.

End to end security protocols

Translation breaks IPsec AH and transport mode ESP. Use protocols that tolerate address changes, such as TLS, or IPsec with UDP encapsulation.

Step by step: build a lab NAT64, DNS64 and CLAT on Linux

The lab has three machines or virtual machines:

HostRoleIPv6IPv4
CIPv6-only client, later with a CLAT2001:db8:64::10/64none
TTranslator (Jool) and DNS64 resolver (Unbound)2001:db8:64::1/64198.51.100.1/24 plus an upstream internet connection
SIPv4-only servernone198.51.100.10/24

We use the documentation prefixes 2001:db8::/32 and 198.51.100.0/24, and a /96 from the local-use prefix, 64:ff9b:1::/96, as the translation prefix. The local-use prefix keeps us clear of the RFC 6052 rule against combining the Well-Known Prefix with non-global IPv4 addresses, which would otherwise apply to our documentation range server. Nothing in this lab survives a reboot unless you make it persistent; the Jool documentation has a separate page on persistence.

1. Address the hosts and enable forwarding on T

# On T
sudo ip link set eth0 up
sudo ip address add 2001:db8:64::1/64 dev eth0
sudo ip link set eth1 up
sudo ip address add 198.51.100.1/24 dev eth1
sudo sysctl -w net.ipv4.conf.all.forwarding=1
sudo sysctl -w net.ipv6.conf.all.forwarding=1

# On C
sudo ip address add 2001:db8:64::10/64 dev eth0
sudo ip route add 64:ff9b:1::/96 via 2001:db8:64::1

# On S
sudo ip address add 198.51.100.10/24 dev eth0

S needs no route back to the IPv6 network. The Jool tutorial explains why: the translator masks the IPv6 nodes, so the IPv4 server thinks it is talking to T directly. Confirm T can ping both C and S before adding the translator.

2. Install Jool on T

Install Jool from your distribution's packages if they carry a current release, or build it from source following the Jool installation guide. On Debian and Ubuntu the guide's build prerequisites include build-essential, pkg-config, the linux-headers package for the running kernel, libnl-genl-3-dev, libxtables-dev and dkms. The project page lists 4.1.15, released on January 26, 2026, as the most mature version, and says development has slowed to essential maintenance, with bug fixing and support still active. Check that the version you install has had the fixes your distribution ships.

# On T, after installation
jool --version
sudo modprobe jool

3. Create a stateful NAT64 instance

# On T
sudo jool instance add "lab" --netfilter --pool6 64:ff9b:1::/96
sudo jool -i "lab" global display

The tutorial configures only the translation prefix. The pool4 documentation explains how to define dedicated IPv4 pool addresses and port ranges, which you should do in production so the translator's management address is not shared with client traffic.

Test from C before DNS is involved. The embedded address of 198.51.100.10 is c633:640a (198 is c6, 51 is 33, 100 is 64, 10 is 0a):

# On C
ping -6 -c 3 64:ff9b:1::198.51.100.10
# the reply source prints as 64:ff9b:1::c633:640a

Do not test from T itself. Jool only translates packets passing through it, and the documentation warns that pinging a translated address from the translator will not work.

4. Turn on mapping logs and filtering

# On T
sudo jool -i "lab" global update logging-bib true
sudo jool -i "lab" global update address-dependent-filtering true
sudo jool -i "lab" global update drop-externally-initiated-tcp true
sudo dmesg --follow | grep 'Mapped\|Forgot'

Open a connection from C to S and watch a Mapped line appear with the IPv6 and IPv4 transport addresses. Leave logging-session off unless your policy requires destination logging. Decide on address-dependent-filtering with your applications in mind; it is the safer default for a lab and for clients that only browse, but it can break peer to peer software.

5. Restrict who can use the translator and where it can go

Add filters on T that run before translation. The chain below hooks prerouting at raw priority, ahead of the mangle stage where the Jool tutorial attaches its iptables rule; confirm with the counters that your rules match before translation on your kernel and Jool version.

# On T: /etc/nftables.d/nat64-guard.nft (load with: sudo nft -f <file>)
table inet nat64guard {
  set blocked_v4_in_v6 {
    type ipv6_addr
    flags interval
    elements = {
      64:ff9b:1::a00:0/104,    # 10.0.0.0/8
      64:ff9b:1::ac10:0/108,   # 172.16.0.0/12
      64:ff9b:1::c0a8:0/112,   # 192.168.0.0/16
      64:ff9b:1::7f00:0/104,   # 127.0.0.0/8
      64:ff9b:1::a9fe:0/112,   # 169.254.0.0/16 (metadata and link-local)
      64:ff9b:1::6440:0/106    # 100.64.0.0/10 (shared address space)
    }
  }
  chain pre {
    type filter hook prerouting priority raw; policy accept;
    # only our clients may send to the translation prefix
    ip6 daddr 64:ff9b:1::/96 ip6 saddr != 2001:db8:64::/64 counter drop
    # nobody may source traffic from the translation prefix (RFC 6146 5.4)
    ip6 saddr 64:ff9b:1::/96 counter drop
    # no translation into internal or metadata ranges
    ip6 daddr @blocked_v4_in_v6 counter drop
  }
}

The prefix lengths follow from the /96: an IPv4 /8 becomes a /104, a /12 becomes a /108, a /16 becomes a /112 and a /10 becomes a /106. If your lab server sits in one of these ranges, add an explicit accept for its single embedded address above the drop rule. Add your own management networks to the set.

6. Configure Unbound as a DNS64 resolver on T

# /etc/unbound/unbound.conf.d/dns64.conf
server:
    interface: 2001:db8:64::1
    access-control: 2001:db8:64::/64 allow
    access-control: ::0/0 refuse
    module-config: "dns64 validator iterator"
    dns64-prefix: 64:ff9b:1::/96

The access control lines matter: an open DNS64 resolver is an open resolver, with all the reflection abuse that brings. Check the configuration and restart:

sudo unbound-checkconf
sudo systemctl restart unbound

Unbound on T resolves names over its own IPv4 upstream. Synthesis only changes the answers it gives to clients, so T's own lookups are not affected.

7. Test discovery with ipv4only.arpa

# On C (or any host that can reach T's resolver)
dig AAAA ipv4only.arpa @2001:db8:64::1 +short
# expected: 64:ff9b:1::c000:aa and 64:ff9b:1::c000:ab

dig AAAA <an IPv4-only name you control> @2001:db8:64::1 +short
dig AAAA <a dual-stack name> @2001:db8:64::1 +short   # real AAAA, unchanged

The first answer proves synthesis and tells any RFC 7050 client the prefix: the two well-known addresses 192.0.0.170 and 192.0.0.171 are c000:aa and c000:ab. The dual stack test proves the resolver passes real AAAA records through untouched. Point C's resolver at 2001:db8:64::1 and browse to an IPv4-only site through the translator while watching the Mapped lines on T.

8. Advertise PREF64 if your router software supports it

Following RFC 9872, send the prefix in router advertisements as well as through DNS64. Router daemons differ, so check your router's documentation for a PREF64 or NAT64 prefix setting. On the client side, systemd-networkd can consume the option through the UsePREF64 setting described in systemd.network(5), which is what clatd reads first. Verify with a packet capture that the RA carries option type 38:

# On C
sudo tcpdump -i eth0 -vv 'icmp6 and ip6[40] == 134'

9. Add a CLAT on the client with clatd

# On C
git clone https://github.com/toreanderson/clatd
sudo make -C clatd install installdeps
sudo clatd -d plat-prefix=64:ff9b:1::/96

Setting plat-prefix explicitly skips discovery; leave it out to test PREF64 or ipv4only.arpa discovery instead. clatd creates a CLAT interface with the IPv4 address 192.0.0.1 and an IPv4 default route. Now test with an IPv4 literal:

# On C, in a second terminal
ip -4 route
ping -c 3 198.51.100.10
curl -4 http://198.51.100.10/

The packets leave C as IPv4, are translated to IPv6 by the CLAT with destination 64:ff9b:1::c633:640a, and are translated back to IPv4 by Jool on T. You will see a Mapped line on T with C's CLAT IPv6 address. Note that clatd enables IPv6 forwarding and adjusts accept_ra on the client, so do not run this on a machine whose routing you care about without reading its documentation first.

10. Clean up

# On C
# stop clatd with Ctrl+C; it restores the settings it changed

# On T
sudo nft delete table inet nat64guard
sudo jool instance remove "lab"
sudo modprobe -r jool

Comparison: dual stack, NAT64 with DNS64, 464XLAT, DS-Lite, MAP-T and MAP-E

Dual stackNAT64 + DNS64464XLATDS-LiteMAP-T / MAP-E
Access networkIPv4 and IPv6IPv6 onlyIPv6 onlyIPv6 onlyIPv6 only
Where IPv4 state livesEvery NAT in the IPv4 path, usually a CGNProvider NAT64Provider NAT64 (PLAT); CLAT is stateless with a dedicated /64Provider AFTRCustomer router only; provider border relay is stateless
How IPv4 crosses the IPv6 networkNativelyTranslated onceTranslated twiceIPv4 in IPv6 tunnelMAP-T translates, MAP-E encapsulates
IPv4 literals and IPv4-only socketsWorkFailWork through the CLATWorkWork
Client needs special softwareNoNo (DNS64 in the network)Yes, a CLATYes, a B4 in the home routerYes, a MAP CE router
End to end IPsec AH or transport ESPWork where no NATFailFailFail through the AFTR NATFail through the CE NAT
DNSSEC validating clientsWorkNeed local synthesis via PREF64 or RFC 7050Same as NAT64 for name based trafficWorkWork
Logging needed for attributionCGN mapping logs if IPv4 is sharedNAT64 BIB logs with timestampsPLAT BIB logs; CLAT address ties to a subscriberAFTR logs per softwire and portStatic port set to subscriber records
Main security workTwo policies to keep in stepSource filtering, mapping logs, RA and DNS integrity, internal range blocksAll of NAT64, plus CLAT host forwarding and RA trustAFTR capacity, tunnel endpoint filteringProvisioning record integrity, port range sizing

RFC 9313 says the right choice depends on existing topology, skills, strategy and other preferences. An enterprise or data centre that controls its clients usually gets the fewest moving parts from NAT64 with DNS64 plus a CLAT where needed; a broadband provider that controls home routers can use the stateless MAP options to avoid central state.

Where Safeguard fits

Safeguard does not run translators, resolvers, router advertisement guards or DHCP snooping, and it does not test whether an app works on an IPv6-only network. The fit here is indirect and narrow. Translators, DNS64 resolvers and CLATs are software, often built from open source projects such as Jool, Unbound, BIND, clatd and TAYGA and shipped as packages, appliances or container images. Safeguard can scan the repositories and container images you build for those services with safeguard scan --dir . or safeguard scan --image <name>, match their components against vulnerability databases, show which projects contain a given component and version, and open fix pull requests (autonomous remediation ships switched off by default). That keeps the resolver image or network automation repository you deploy from carrying known vulnerable dependencies. The translation policy, logging and access controls described above remain your network team's job.

Common mistakes

  • Treating DNS64 as access control. Clients can type Pref64:: plus any IPv4 address or synthesise locally. Enforce destination policy on the translator or firewall.
  • Using a Network-Specific or local-use prefix without internal range filters. Only the Well-Known Prefix carries the RFC 6052 rule against non-global IPv4 addresses. With any other prefix, a client can reach RFC 1918, loopback and metadata ranges unless you block them.
  • Running an open translator or open DNS64 resolver. Restrict both to your own client prefixes and do not advertise the translation prefix outside its intended domain.
  • Allowlisting the NAT64 pool address on internal IPv4 services. Every IPv6 client inherits the trust. Give the pool its own addresses with no special rights.
  • Turning on mapping logs without time sync or retention. A log line without an accurate timestamp and a matching port cannot identify anyone.
  • Deploying PREF64 or DNS64 discovery on a network without RA-Guard and DHCP guard. Both discovery methods trust the local link and the local resolver.
  • Mismatched prefixes. The DNS64 prefix, the NAT64 pool6, the PREF64 option and any CLAT plat-prefix must all agree.
  • Building synthesised addresses by hand in application code. Apple's documentation warns that combining an IPv4 address with 64:ff9b::/96 is not a general solution. Use the system resolver and address family agnostic APIs.
  • Forgetting MTU. IPv6 headers are 20 bytes larger than IPv4 headers, and Jool's documentation suggests setting lowest-ipv6-mtu to the minimum MTU across your IPv6 networks so translated IPv4 packets without the Don't Fragment flag are fragmented to fit.

FAQ

What is the difference between NAT64 and DNS64?

NAT64 translates packets between IPv6 and IPv4 at the network layer. DNS64 is a resolver feature that creates AAAA records for IPv4-only names, so IPv6 clients send their packets to the NAT64. You normally deploy them together with the same prefix, but they are separate functions defined in RFC 6146 and RFC 6147.

What is 64:ff9b::/96?

It is the Well-Known Prefix defined in RFC 6052 for embedding IPv4 addresses in IPv6 addresses for translation. The IPv4 address fills the last 32 bits, so 192.0.2.33 becomes 64:ff9b::c000:221. It must not be used to represent private or other non-global IPv4 addresses.

What is 64:ff9b:1::/48 used for?

RFC 8215 reserved it in August 2017 for local use inside a network that runs translation. It lets operators run several translation mechanisms, or translate to private IPv4 addresses, without using their own global IPv6 space. You must add your own filters, since the Well-Known Prefix restrictions do not apply.

Why does DNS64 break DNSSEC?

DNSSEC detects modified answers and DNS64 modifies answers. A client that validates for itself sees a synthesised AAAA record without a valid signature and rejects it. Such clients need to learn the prefix and synthesise locally after validating the real A record.

What is ipv4only.arpa?

A name with only two A records, 192.0.0.170 and 192.0.0.171. A host that gets an AAAA answer for it knows the resolver does DNS64 and reads the prefix out of the answer. RFC 7050 defined it; RFC 8880 registered it as a special use name.

What is the PREF64 option?

It is a router advertisement option, type 38, defined in RFC 8781 in April 2020, that carries the NAT64 prefix, its length and a lifetime. RFC 9872 recommends that hosts prefer it over the ipv4only.arpa method and that operators send it.

What is a CLAT in 464XLAT?

The customer side translator. It gives the host an IPv4 address and default route and translates IPv4 packets statelessly into IPv6 towards the provider's NAT64 (the PLAT), so IPv4 literals and IPv4-only sockets work.

What does DHCP option 108 do?

It is the IPv6-Only Preferred option from RFC 8925. A device that can run on IPv6 alone asks for it, and a server on an IPv6-mostly network replies with a number of seconds during which the device should not configure IPv4. The default wait is 1800 seconds and the minimum is 300.

Is NAT64 a security boundary?

Only to the extent that its filtering is configured. RFC 6146 says security properties come from filtering behaviour and configuration, not from address mapping. Treat it as a translator that needs source restrictions, destination restrictions and logs, not as a firewall.

Do IPv4-only servers need changes to serve IPv6-only clients?

Usually not. Apple's developer documentation says servers on the wider internet are reachable through DNS64 and NAT64, though they should eventually add IPv6. The server sees the translator's address, not the client's, which affects logging and rate limiting.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.

3. Gold Registry: start from components that are already fixed

Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingSafeguard policies and gates in CI
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo is a real session with the Safeguard CLI. The assistant reads a finding and its advisory, asks before each command, upgrades a dependency, runs the tests and pushes nothing. The same flow applies when the repository that builds your DNS64 resolver image or your network automation tooling carries a vulnerable library.

Click through it at your own pace, or open it full screen.

The second demo sets up the Safeguard runner on your own machine, approves it with a device code and then scans from the terminal. Translator and resolver configurations often live on internal hosts that should not be exposed, and the runner lets you scan them from a machine you control.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. Choosing a narrow set of tools is the same habit as restricting a NAT64 to your own client prefixes: allow only what each party needs.

Click through it at your own pace, or open it full screen.

Download the apps at safeguard.sh/download and read the CLI docs at docs.safeguard.sh/docs/cli.

Quick check

Your DNS64 uses the prefix 64:ff9b:1::/96. What AAAA record does it return for ipv4only.arpa, and what would it return for an IPv4-only name at 203.0.113.16?

For ipv4only.arpa it returns 64:ff9b:1::c000:aa and 64:ff9b:1::c000:ab, the embedded forms of 192.0.0.170 and 192.0.0.171. For 203.0.113.16 it returns 64:ff9b:1::cb00:7110, because 203 is cb, 0 is 00, 113 is 71 and 16 is 10.

A router advertises PREF64 with a Scaled Lifetime of 225. How long is the prefix valid, and what is the longest lifetime the option can carry?

225 x 8 = 1800 seconds, or 30 minutes. The field is 13 bits, so the maximum is 8191 x 8 = 65528 seconds, a little over 18 hours.

Sources

Related reading: IPv4 vs IPv6, SLAAC, DHCPv6 and privacy addresses, What NAT does and does not secure, Run your own DNS resolver and ARP and IPv6 Neighbor Discovery.

Last reviewed: 24 October 2026. Translator and resolver options change between releases; check the documentation for the versions you deploy before relying on a specific default or behaviour.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.