Aug 24, 2026·6 min read·22 visits
Unvalidated ALPN parsing in netfoil permits terminal log injection and memory exhaustion.
netfoil, an allowlist-based DNS proxy, failed to sanitize ALPN fields parsed from untrusted DNS-over-HTTPS (DoH) HTTPS Resource Records. This allowed attackers to inject ANSI escape sequences into log files or trigger Denial of Service (DoS) via uncontrolled memory allocations.
netfoil is a client-side, minimal DNS proxy built in Go that relies on DNS-over-HTTPS (DoH) to secure upstream queries and apply allowlists.
During standard resolution operations, the proxy parses incoming DNS resource records, including HTTPS Resource Records (RR) defined by RFC 9460. These records contain Application-Layer Protocol Negotiation (ALPN) parameters used to negotiate client-server protocol capabilities.
Prior to version v0.5.0, netfoil did not validate or sanitize the parsed ALPN parameters. Any raw byte sequence returned in the ALPN field by an upstream server was converted directly into Go strings and subsequently logged or stored.
This lack of validation exposed the proxy to log poisoning via ANSI escape sequence injection and denial of service via memory exhaustion. In addition, the system lacked structured logging for single-byte DNS response codes (RCODE), logging raw numbers directly to standard output.
The vulnerability is situated within the parsing function readALPN in internal/dns/dns_https.go. This function processes raw byte slices containing ALPN identifiers.
RFC 9460 defines the ALPN parameter in HTTPS records as a list of length-prefixed protocol identifiers. The unpatched readALPN implementation sequentially read each identifier via a helper function readPart and converted the raw bytes directly to a Go string.
No checks were performed to verify if the converted strings matched legitimate ALPN values, nor were there limitations on the number of unique or repetitive strings parsed.
An attacker capable of manipulating the upstream DNS response could inject non-printable characters, terminal escape sequences, or millions of duplicate keys. The proxy would attempt to process and store all incoming values, causing excessive memory allocations and terminal-side command execution through output manipulation.
Below is the comparison of the vulnerable implementation versus the patched implementation in internal/dns/dns_https.go.
// VULNERABLE: internal/dns/dns_https.go
func readALPN(data []byte) ([]string, error) {
p := bytes.NewBuffer(data)
parts := make([]string, 0)
for {
if p.Len() == 0 {
break
}
part, err := readPart(p)
if err != nil {
return nil, err
}
parts = append(parts, string(part)) // Direct unvalidated conversion
}
return parts, nil
}The patch introduced strict allowlist matching and a uniqueness check using a map-based set to control memory footprint.
// PATCHED: internal/dns/dns_https.go
func readALPN(data []byte) ([]string, error) {
p := bytes.NewBuffer(data)
alpnSet := make(map[string]struct{})
result := make([]string, 0)
for {
if p.Len() == 0 {
break
}
part, err := readPart(p)
if err != nil {
return nil, err
}
alpn := string(part)
switch alpn {
case "h2":
_, found := alpnSet[alpn]
if !found {
result = append(result, alpn)
alpnSet[alpn] = struct{}{}
}
case "h3":
_, found := alpnSet[alpn]
if !found {
result = append(result, alpn)
alpnSet[alpn] = struct{}{}
}
default:
// Safe fallback: silently drop unapproved values
}
}
return result, nil
}The fix successfully mitigates both log injection and resource consumption. By explicitly restricting valid ALPN tokens to a static switch case ("h2" and "h3"), all arbitrary string conversions are eliminated. The use of alpnSet enforces a maximum slice capacity of two elements, blocking the duplicate exhaustion vector completely.
Exploitation of this vulnerability requires the attacker to control the DNS resolution path of the client using netfoil.
This can be achieved by hijacking an upstream DoH resolver, poisoning the cache of an intermediate resolver, or setting up a malicious authoritative nameserver for a domain queried by the target client.
To perform terminal escape sequence injection, the attacker crafts an HTTPS resource record where the ALPN field contains ANSI escape codes such as \x1b[2J\x1b[H (Clear Screen) or sequences designed to manipulate terminal scrollback and inject arbitrary output lines.
When the proxy resolves the target domain, the raw escape sequences are parsed and written directly to standard output by the logging routine. If the administrator views the logs in an active terminal emulator, the emulator processes the escape sequence, executing the actions locally.
For a Denial of Service attack, the attacker crafts an HTTPS resource record containing a long loop of identical or unique fake ALPN entries. The unpatched proxy continually allocates new memory for the parts slice until the host system encounters an Out of Memory (OOM) condition and kills the process.
The primary impact of this vulnerability is local denial of service and log manipulation.
Because netfoil acts as an allowlist-based DNS proxy, terminating the process disrupts local resolution entirely or bypasses security policies if fallback mechanisms are configured to permit unproxied traffic.
Log poisoning through ANSI injection presents a moderate threat to administrative integrity. It can hide security warnings, falsify system status messages, or spoof user interactions in active terminals.
This vulnerability has been assigned a CVSS score of 6.5 (Medium), reflecting the high requirement of network position or upstream control, coupled with the potential for host-level availability loss and log tampering.
Remediation requires updating the netfoil package to version v0.5.0 or later.
To update the dependency in a Go project, execute the following command:
go get -u github.com/tinfoil-factory/netfoil@v0.5.0If upgrading immediately is not feasible, administrators should enforce the use of trustworthy, verified upstream DoH resolvers (such as Cloudflare or Google DNS) that filter out malformed or suspicious resource records prior to delivery.
Additionally, standard output streams from netfoil can be sanitized through log forwarding utilities to strip control characters before they reach interactive terminal sessions.
For example, administrators can pipe log outputs through a sanitization utility:
./netfoil | tr -cd '\11\12\15\40-\176'CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
netfoil tinfoil-factory | < v0.5.0 | v0.5.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-117, CWE-20, CWE-400 |
| Attack Vector | Network (DNS Response Control Required) |
| CVSS v3.1 Score | 6.5 |
| Impact | Denial of Service, Log Manipulation |
| Exploit Status | None |
| KEV Status | Not Listed |
The software does not neutralize or incorrectly neutralizes output written to logs, allowing malicious input to alter log structures or run terminal-side payload sequences.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.
CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.
An elevation of privilege vulnerability exists in ASP.NET Core and Microsoft Visual Studio due to improper synchronization during concurrent thread execution. Authenticated remote attackers with low privileges can exploit a timing window to manipulate shared resources and assume higher-level execution contexts.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.