ZeroPath at Black Hat USA 2026

Brief Summary: AdGuard Home CVE-2026-41448 Path Traversal Authentication Bypass in GL.iNet Router Mode

A short review of CVE-2026-41448, a critical path traversal authentication bypass in AdGuard Home's GL.iNet integration mode, including patch analysis and affected configurations.

CVE Analysis

10 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-06-08

Brief Summary: AdGuard Home CVE-2026-41448 Path Traversal Authentication Bypass in GL.iNet Router Mode
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A single crafted cookie is all it takes to gain full administrative control over AdGuard Home instances running on GL.iNet routers, granting an attacker the ability to manipulate DNS resolution for every device on the network. CVE-2026-41448, scored at CVSS v3 9.4 and CVSS v4 9.2, is a path traversal authentication bypass in AdGuard Home's authglinet middleware that turns an unsanitized file path into a complete security failure.

AdGuard Home is an open source, network wide DNS filtering server that blocks ads and tracking at the DNS level for all devices on a network without requiring client side software. It has a substantial user base, particularly through its integration with GL.iNet routers (models like the Flint 3, Beryl 7, and Slate 7), where it ships as the built in DNS filtering layer. This makes it a critical piece of network infrastructure in home and small business environments worldwide.

Technical Information

CVE-2026-41448 is classified under CWE-22: Improper Limitation of a Pathname to a Restricted Directory. The vulnerability exists exclusively when AdGuard Home is launched with the --glinet command line flag, which activates the authglinet middleware. This middleware is a separate authentication module designed specifically for GL.iNet router integration.

The core issue is straightforward: the middleware constructs a filesystem path by concatenating a static prefix with the value of the Admin-Token cookie, then opens that path to read and validate the authentication token. Prior to the patch, the prefix was defined as a mutable package level variable:

// BEFORE (internal/home/authglinet.go) var glFilePrefix = "/tmp/gl_token_"

When a request arrived, the cookie value was appended directly to this prefix to form the full file path. No sanitization, no validation, no directory confinement. A cookie value containing ../ sequences would cause the resulting path to escape the intended /tmp/ directory entirely.

Attack Flow

The exploitation sequence is direct:

  1. The attacker identifies an AdGuard Home instance running with the --glinet flag (the default on GL.iNet routers).
  2. The attacker sends an HTTP request to the AdGuard Home web interface with a crafted Admin-Token cookie containing path traversal sequences (e.g., ../../ followed by a known file path).
  3. The authglinet middleware concatenates this unsanitized cookie value with the /tmp/gl_token_ prefix, producing a path like /tmp/gl_token_/../../etc/some_file.
  4. The middleware opens this traversed path using os.Open and reads its contents.
  5. If the file read succeeds and the returned content satisfies the token validation logic, the middleware grants full administrative access.
  6. The attacker now has complete control over the AdGuard Home instance: DNS filtering rules, upstream DNS servers, DHCP settings, and all connected device DNS resolution.

CVSS Scoring

The CVSS v4 vector assigned by VulnCheck is CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N. The AT:P (Attack Requirements: Present) reflects the requirement that the target must be running with the --glinet flag. On GL.iNet routers, this is the default configuration, making it a condition rather than a barrier.

MetricValue
Attack VectorNetwork
Attack ComplexityLow
Privileges RequiredNone
User InteractionNone
Confidentiality ImpactHigh
Integrity ImpactHigh
Availability ImpactLow

Impact

Full administrative access to AdGuard Home in a GL.iNet router deployment means control over the network's primary DNS resolver. An attacker can redirect DNS queries to malicious servers, modify blocklists to allow malicious domains, alter DHCP configurations, and silently surveil all DNS traffic. DNS level manipulation is particularly insidious because it is difficult to detect without dedicated monitoring infrastructure, which is rarely present in the home and small office environments where GL.iNet routers are deployed.

Discovery

The vulnerability was discovered by security researcher djnn (GitHub: @djnnvx) and coordinated through VulnCheck, which served as the CVE Numbering Authority.

Patch Information

AdGuard Home v0.107.77, released June 2, 2026, addresses CVE-2026-41448 with a well structured fix that eliminates the path traversal vector at the filesystem API level rather than relying on input sanitization. The changes are visible in the diff between v0.107.76 and v0.107.77.

Eliminating the Mutable Path Prefix

The first change converts the token file prefix from a mutable variable containing a full filesystem path to a constant containing only the filename prefix:

// BEFORE (internal/home/authglinet.go) var glFilePrefix = "/tmp/gl_token_" // AFTER (internal/home/authglinet.go) const glFilePrefix = "gl_token_"

This strips the directory component entirely, removing the ability for the prefix itself to be manipulated and ensuring the filename portion is a compile time constant.

Introducing os.Root for Directory Confinement

The patch replaces the tokenFilePrefix string configuration field with a tokenFileRoot *os.Root field. This uses Go 1.24's os.OpenRoot facility, which creates a handle to a directory that cannot be escaped via path traversal. The root is opened at startup:

if opts.glinetMode { glTokenFileRoot, err = os.OpenRoot("/tmp/") fatalOnError(err) }

This *os.Root value is threaded through the configuration structs (authConfig, authMiddlewareGLiNetConfig) into the middleware.

Replacing os.Open with Sandboxed Open

The critical change is in the tokenDate method where the token file is actually opened:

// BEFORE f, err := os.Open(tokenFile) // AFTER f, err := mw.tokenFileRoot.Open(tokenFile)

os.Root.Open() resolves paths relative to the root directory and rejects any traversal sequences. A cookie value like /../../etc/passwd will no longer escape the /tmp/ sandbox.

Test Coverage

The patch adds explicit test cases that attempt path traversal and verify it fails:

reqPathTraversalToken := httptest.NewRequest(http.MethodGet, "/", nil) reqPathTraversalToken.AddCookie(&http.Cookie{ Name: glCookieName, Value: "/../../path_traversal_token", })

The test asserts that this request results in an HTTP 302 redirect to the login page, confirming the traversal is blocked.

This is a textbook example of defense in depth: rather than attempting to sanitize the input (which is error prone), the fix confines the filesystem operation to a specific directory at the OS level, making traversal structurally impossible.

Affected Systems and Versions

All versions of AdGuard Home prior to v0.107.77 are affected when running with the --glinet command line flag. Specifically:

  • Affected: AdGuard Home versions before 0.107.77 launched with --glinet
  • Not affected: AdGuard Home instances running without the --glinet flag (standard deployments)
  • Fixed in: AdGuard Home v0.107.77 (released June 2, 2026)

The --glinet flag is the default integration mode on all GL.iNet router models that bundle AdGuard Home, including but not limited to:

  • GL.iNet Flint 3 (GL-BE9300)
  • GL.iNet Beryl 7 (GL-MT3600BE)
  • GL.iNet Slate 7 (GL-BE3600)

GL.iNet router firmware updates lag behind upstream AdGuard Home releases. Even after AdGuard Home v0.107.77 was released, GL.iNet users may remain exposed until a firmware update incorporating the patched version is issued. The GL.iNet forum has an active thread discussing this update lag, with users asking when patches would be incorporated into firmware.

Vendor Security History

CVE-2026-41448 is the second critical authentication bypass in AdGuard Home in 2026. The first, CVE-2026-32136 (CVSS 9.8), was disclosed in March 2026 and fixed in v0.107.73. That vulnerability exploited the HTTP/2 Cleartext (h2c) upgrade mechanism: the authentication wrapper only applied to the initial HTTP/1.1 upgrade request, leaving h2c connections unauthenticated and able to access admin endpoints. GL.iNet forum staff published a proof of concept for that flaw.

AttributeCVE-2026-32136CVE-2026-41448
CVSS Score9.89.4 / 9.2 (v4)
CWEAuth bypass via protocolCWE-22 (Path Traversal)
Attack VectorHTTP/2 h2c upgradePath traversal in Admin-Token cookie
Affected ModeAll deployments--glinet flag only
Fixed Versionv0.107.73v0.107.77

AdGuard Home has accumulated at least 8 documented CVEs according to OpenCVE. Earlier vulnerabilities CVE-2022-30580 and CVE-2022-29804 were addressed in a release that also introduced enforced password protection. A security bulletin covering five vulnerabilities was issued in March 2024.

The two critical authentication bypasses within three months share a common pattern: the authentication middleware has multiple independent logic paths, and flaws in any single path result in complete bypass. CVE-2026-32136 exploited a protocol level weakness; CVE-2026-41448 exploits a classic input validation failure. Both achieve the same outcome through entirely different mechanisms, indicating that the authentication layer has multiple independent failure modes. This suggests a need for a comprehensive authentication architecture review rather than continued point fixes.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Jira
  • Linear
  • Slack
  • Security Compass
Security magnifying glass visualization