Skip to content

fix: stop the WOPI keys from leaking and let the environment configure them - #546

Open
DeepDiver1975 wants to merge 3 commits into
masterfrom
fix/remaining-secret-env-vars
Open

fix: stop the WOPI keys from leaking and let the environment configure them#546
DeepDiver1975 wants to merge 3 commits into
masterfrom
fix/remaining-secret-env-vars

Conversation

@DeepDiver1975

Copy link
Copy Markdown
Contributor

Follow-up to #543, from the same 10.16.4 report. #543 got the eight secrets the
base image itself handles down to zero log hits, but the reporter's wopi.token.key
and their ONLYOFFICE jwt_secret still showed up. Root cause: those two never went
through the image's own scripts at all — they were set from a custom hook, because
v22.04 has no WOPI environment variables even though ENVIRONMENT.md documents
them. Three secret env vars were also missed by #543.

Scoped to v22.04 and v24.04; v20.04 is dormant and untouched.

1. The three variables #543 missed (#544)

OWNCLOUD_WOPI_TOKEN_KEY and OWNCLOUD_METRICS_SHARED_SECRET (v24.04) and
OWNCLOUD_PROXY_USERPWD (both variants) still used the plain
[[ -z "${VAR}" ]] test, so DEBUG=true printed them. They now use "${VAR:+x}"
like the already covered secrets.

2. WOPI keys from the environment (#545)

The wopi app reads both wopi.token.key and wopi.proxy.key through
getSystemValue(), so they can come from the generated config file and never have
to touch occ. Added OWNCLOUD_WOPI_PROXY_KEY, which was missing in both variants,
and backported the whole OWNCLOUD_WOPI_* family to v22.04 — the variant behind
10.16.4, 10.16, 10 and latest, which implemented none of it.

That is the actual fix for the reported disclosure: with the variables in place no
hook is needed, and the generated config file is never echoed or traced.

3. Docs

The hook directories were undocumented in this repo. README.md now describes
them, says to prefer a documented environment variable over a hook, and shows how
to keep a secret out of the log when a hook has to call occ anyway:

{ set +x; } 2>/dev/null                                            # no shell trace
occ config:app:set onlyoffice jwt_secret --value "${SECRET}" -q     # no echo
[[ "${DEBUG}" == "true" ]] && set -x

This is what admins of apps that are not bundled in the image (onlyoffice,
richdocuments) need, since they have no environment variable to use. It is
documented together with its limitation: admin_audit still records the full
argument list. Both remaining leaks are upstream and now filed —
owncloud/core#41779 (the command echoes the value back) and
owncloud/admin_audit#461 (the audit entry contains the argv).

Verification

Real images, not the overlay in isolation: owncloud/base built from this branch
for both variants, with owncloud/server:10.16.4 / 11.0.0 layered on top, against
MySQL 8 + Redis, DEBUG=true, and eight secrets in the environment.

v22.04 / 10.16.4 v24.04 / 11.0.0
container Up, status.php installed:true, PROPFIND 207 Up, status.php installed:true, PROPFIND 207
xtrace lines 867 1042
hits for any of the 8 secrets in docker logs 0 0
hits in owncloud.log 0 0
trace of the new secrets [[ -z x ]] [[ -z x ]]

occ config:system:get returns all six WOPI values plus metrics_shared_secret
and proxyuserpwd from the environment on both variants.

The keys are really consumed, not just stored — occ wopi:get-token on 10.16.4
returns two JWTs, and verifying their HMAC signatures shows which key signed what:

token vs OWNCLOUD_WOPI_TOKEN_KEY vs OWNCLOUD_WOPI_PROXY_KEY
access token match no match
business-proxy wopi_src no match match

Setting both variables to the same value makes the app raise
System configuration <wopi.proxy.key> and <wopi.token.key> are identical.
(TokenService.php:163), which confirms both arrive from the environment.

The documented hook pattern was checked against the reporter's original hook,
running side by side in one container:

hook hits for the secret in docker logs
as reported 2 (xtrace line + occ echo)
with set +x and -q 0

and the residual limitation was confirmed rather than assumed — with the hardened
hook, owncloud.log still holds
command_executed … config:app:set onlyoffice jwt_secret --value … -q.

shellcheck clean on both hooks, php -l clean on both templates.

Follow-up

owncloud-docker/server needs its FROM owncloud/base:... digests bumped once this
is published (Renovate normally does this).

🤖 Generated with Claude Code

…utput

The xtrace hardening in #543 missed three secret-bearing variables that
still tested their value with the plain "[[ -z ${VAR} ]]" form, so
DEBUG=true printed them: OWNCLOUD_WOPI_TOKEN_KEY and
OWNCLOUD_METRICS_SHARED_SECRET (v24.04) and OWNCLOUD_PROXY_USERPWD (both
variants, a user:password pair).

Test them as "${VAR:+x}" like the already covered secrets, so the trace
shows "[[ -z x ]]" instead of the value.

Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
The wopi app reads wopi.token.key and wopi.proxy.key through
getSystemValue(), so both can come from the generated config file and
never have to pass through "occ config:system:set" — which echoes the
value back to stdout and is recorded verbatim by admin_audit.

Add OWNCLOUD_WOPI_PROXY_KEY, and backport the whole OWNCLOUD_WOPI_*
family to v22.04, which had no WOPI support at all even though
ENVIRONMENT.md documents the variables without a variant caveat. Admins
on 10.16.x therefore had to configure the keys from a custom hook.

Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Add OWNCLOUD_WOPI_PROXY_KEY to ENVIRONMENT.md and a README section for the
hook directories, which were undocumented in this repo. It states that a
documented environment variable is preferable to a hook, and shows how to
keep a secret out of the log when a hook has to call occ anyway.

Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant