Skip to content

tunnel route dns <name> <hostname> routes to the tunnel in the configured credentials file, ignoring the name argument #1762

Open

Description

@jtannahill

Describe the bug

When the tunnel is passed by name and a credentials file is configured (for example through credentials-file in ~/.cloudflared/config.yml for a different tunnel), cloudflared tunnel route dns <name> <hostname> creates the CNAME for the tunnel in that credentials file, not the tunnel named on the command line. The command succeeds, and the only sign of the mismatch is the tunnelID= in the success log line.

Cause: subcommandContext.findID (cmd/cloudflared/tunnel/subcommand_context.go) does this for a non-UUID input:

// Look up name in the credentials file.
credFinder := newStaticPath(sc.c.String(CredFileFlag), sc.fs)
if credentials, err := sc.readTunnelCredentials(credFinder); err == nil {
    if credentials.TunnelID != uuid.Nil {
        return credentials.TunnelID, nil
    }
}

It returns the credentials file's TunnelID without comparing it to input. connection.Credentials holds no tunnel name, so it cannot be compared there. Any configured credentials file therefore wins over the name the user typed. findID is also used by the commands at subcommands.go lines 535, 815 and 876, so they are likely affected the same way.

To Reproduce

  1. Have two named tunnels, tunnel-a and tunnel-b.
  2. ~/.cloudflared/config.yml:
    tunnel: <tunnel-a UUID>
    credentials-file: /path/to/<tunnel-a UUID>.json
  3. Run cloudflared tunnel route dns tunnel-b app.example.com
  4. The command reports success, but the log line shows tunnelID=<tunnel-a UUID> and the CNAME app.example.com points to <tunnel-a UUID>.cfargotunnel.com.

Workarounds: pass the tunnel UUID instead of its name (UUIDs return early in findID), or run with --config /dev/null.

Expected behavior

The name on the command line is honoured. Either the name is resolved via the API when it is given, or cloudflared errors out (or at least warns) when the credentials file's tunnel is not the named tunnel.

The obvious fix (always resolve names via Tunnelstore) would change behaviour for credentials-file-only setups that rely on this shortcut for tunnel run <name>, which is why I'm reporting rather than sending a PR. For route dns / route lb, an origin certificate and API call are needed anyway, so resolving the name via the API there seems safe.

Environment and versions

  • OS: macOS 27.0
  • Architecture: ARM (Apple Silicon)
  • Version: 2026.3.0; the same code is on master today

Logs and errors

The success line names the wrong tunnel, for example:

INF Added CNAME app.example.com which will route to this tunnel tunnelID=<tunnel-a UUID>

Additional context

Hit this in practice: a staging hostname was routed to an unrelated tunnel that happened to be named in config.yml. It was only noticed because the hostname returned 404.

Activity

  1. dedsec-terminal commented on Oct 14, 2026

    @dedsec-terminal

    Opened #1765 resolving this by having findID query Tunnelstore (sc.tunnelActive(input)) first when input is a tunnel name.

    If Tunnelstore is reachable and finds the tunnel by name, its ID is returned directly—preventing a configured credentials file for another tunnel from taking precedence. If Tunnelstore is unreachable (e.g. credentials-file-only execution without an origin certificate), it falls back to reading the configured credentials file so existing credential-only workflows remain supported. Unit tests added covering both the Tunnelstore lookup and fallback paths.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions