Credentials in source query strings are not masked in /api/streams or the log
#1744 masks values that come from env:/${VAR}/CREDENTIALS_DIRECTORY, and
#2051 strips ://user:pass@ userinfo from /api/streams and log output. Neither
covers a credential written literally in a query string, which is how several
sources carry them:
nest:?client_id=&client_secret=&refresh_token=ring:?refresh_token=/password=tuya:client_secret=/password=hass:token=,webtorrent:pwd=,roborock:key=, xiaomi legacypassword=
Connection.URL is populated from the raw source string per backend
(pkg/nest/client.go:120, pkg/rtsp/client.go:78, internal/http/http.go:57,
internal/exec/exec.go:276) and marshalled unfiltered
(pkg/webrtc/conn.go:150, pkg/rtsp/producer.go:112). creds.SecretResponse
wraps the writer at internal/streams/api.go:14, but the replacer only knows
values that were registered, and the userinfo regexp does not match ?key=value.
The same string reaches the log through log.Warn().Err(err).Str("url", p.url)
at internal/streams/producer.go:170 on every Start() error at the default
info level, and at Debug/Trace on lines 152, 181, 185 and 260.
On my instance (1.9.14 base, Nest configured with literal values) each of four
connected streams shows .producers[0].url of length 431 beginning nest:?client.
Frigate users are the common case, since Frigate generates the go2rtc config with
literal values, and a Nest refresh_token plus client_secret stays valid until
revoked from the Google account's third-party access page. /api/config already
returns the whole file, so this is not new exposure to someone with API access.
The cost is that /api/streams output and logs are what people paste into issues
here. In #2351 a contributor suppressed his fatal-error log to keep the URL out
of the line 170 warning and then had no timestamp for the event he was testing.
Proposed fix, in pkg/creds/secrets.go next to userinfoRegexp:
([?&](client_secret|refresh_token|access_token|token|password|pass|pwd|api_key|key)=)[^&#\s"']+ -> $1***applied in SecretString/SecretWrite, so /api/streams, /api/streams.dot,
ws errors and the log writer all pick it up with no per-site changes.
client_id, project_id, device_id, host and path stay visible for diagnosis.
Alternatively each handler can creds.AddSecret() the values it parses in
Dial, reusing the existing replacer. Happy to send either as a PR.
Source: AlexxIT/go2rtc