Skip to content

universal-cloudflared: keep CF_* secrets out of cloudflared's environment - #1167

Merged
thespad merged 1 commit into
linuxserver:universal-cloudflaredfrom
tenfourty:redact-cf-secrets-from-cloudflared-env
Aug 31, 2026
Merged

universal-cloudflared: keep CF_* secrets out of cloudflared's environment#1167
thespad merged 1 commit into
linuxserver:universal-cloudflaredfrom
tenfourty:redact-cf-secrets-from-cloudflared-env

Conversation

@tenfourty

@tenfourty tenfourty commented Aug 31, 2026

Copy link
Copy Markdown

linuxserver.io


  • I have read the contributing guideline and understand that I have made the correct modifications

Description:

cloudflared logs its entire environment at INFO level on startup. It redacts
secrets, but only for variables whose names begin with TUNNEL_ (plus known secret
flags such as --token). This mod's variables are named CF_TUNNEL_PASSWORD,
CF_API_TOKEN and CF_REMOTE_MANAGE_TOKEN, so they fall outside that filter and are
written to the container log verbatim:

INF Environmental variables map[CF_TUNNEL_CONFIG:... CF_TUNNEL_NAME:homelab
    CF_TUNNEL_PASSWORD:<plaintext> TUNNEL_ORIGIN_CERT:/config/...]

This change strips those three variables from cloudflared's environment at exec
time in svc-mod-universal-cloudflared/run.

They are not needed by that point. init-mod-universal-cloudflared-setup has already
derived TunnelSecret from CF_TUNNEL_PASSWORD, written
/etc/cloudflared/${CF_TUNNEL_ID}.json, and emitted
credentials-file: /etc/cloudflared/${CF_TUNNEL_ID}.json into config.yml
so cloudflared authenticates from the credentials file, not the environment.

The existing guards are unaffected because they are evaluated before the exec, and
--token ${CF_REMOTE_MANAGE_TOKEN} still receives its value because bash expands it
before env removes it from the child's environment.

Benefits of this PR and context:

The tunnel secret is currently readable by anyone who can run docker logs on the
container, or through any log viewer pointed at it, and it persists for as long as
the log history is kept. Users have no way to avoid this short of lowering
loglevel, which also suppresses normal connection and registration logging and
brings the secret straight back for anyone who raises the level again to debug.

Two alternatives were considered and rejected:

  • Lowering loglevel to warn — hides the dump but loses useful logging, and
    only masks the problem.
  • Renaming the variables to TUNNEL_* so cloudflared's own scrubber catches
    them — cleaner in principle, but a breaking change for every existing user.

How Has This Been Tested?

Tested on a running lscr.io/linuxserver/swag container with this mod enabled
(cloudflared 2026.8.2, named tunnel authenticating from the credentials file), by
replacing the live service script under /run and restarting only that s6 service
with s6-svc -r.

Variables appearing in cloudflared's startup environment dump:

before CF_TUNNEL_CONFIG, CF_TUNNEL_NAME, CF_TUNNEL_PASSWORD, TUNNEL_ORIGIN_CERT
after CF_TUNNEL_CONFIG, CF_TUNNEL_NAME, TUNNEL_ORIGIN_CERT

The tunnel re-registered all four QUIC connections normally and the proxied hostnames
continued to serve (HTTP 200). bash -n passes on the modified script.

Only the CF_TUNNEL_* / CF_API_TOKEN branch was exercised; I do not have a
CF_REMOTE_MANAGE_TOKEN setup to test the first branch, though the change there is
identical in form.

Source / References:

cloudflared logs its whole environment at INFO on startup and only
redacts variables named TUNNEL_*, so CF_TUNNEL_PASSWORD, CF_API_TOKEN
and CF_REMOTE_MANAGE_TOKEN are written verbatim to docker logs.

The setup step has already written the tunnel credentials file and
referenced it from config.yml, so cloudflared authenticates from that
and no longer needs these values in its environment. Strip them at exec.

The guards are unaffected as they run before the exec, and --token still
receives its value because bash expands it before env removes it.
@tenfourty

Copy link
Copy Markdown
Author

btw - I think your CI is currently broken.

@github-project-automation github-project-automation Bot moved this from PRs to PRs Approved in Issue & PR Tracker Aug 31, 2026
@thespad

thespad commented Aug 31, 2026

Copy link
Copy Markdown
Member

It's not broken per se, it just fails for 3rd party PRs since they changed the restrictions on pull_request_target because Github's workflow approvals system is busted.

@thespad
thespad merged commit 818d0a7 into linuxserver:universal-cloudflared Aug 31, 2026
2 of 3 checks passed
@LinuxServer-CI LinuxServer-CI moved this from PRs Approved to Done in Issue & PR Tracker Aug 31, 2026
@tenfourty

Copy link
Copy Markdown
Author

Brilliant, thank you!

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

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

3 participants