Skip to content

[SECURITY] Discourse deployment leaks secret salt and debugging details #378

Description

@kot0dama

Bug Description

Hi,

When running Discourse-k8s charm, it seems when there are redis availability issues, Discourse app seems to intermittently display the debug page, leaking details on the deployment settings and sometimes including the salt for encrypting sessions.

There should be a way to make sure Discourse does not display debugging data in production.
I could not find a relevant configuration option on https://charmhub.io/discourse-k8s/configurations

Thank you!

To Reproduce

  1. Deploy discourse-k8s charm
  2. Deploy redis storage cache charm
  3. Make redis unavailable (k8s cluster issues, volume issues)

Environment

discourse-k8s revision 183 (latest/stable)
Juju controller 3.1.8

Relevant log output

Redis::CannotConnectError at /t/ubuntu-25-04-sddm-login-on-dual-monitor/67638
Error connecting to Redis on redis-k8s-0.redis-k8s-endpoints.REDACTED-k8s.svc.cluster.local:6379 (Errno::ECONNREFUSED)
Ruby 	/srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in rescue in establish_connection, line 398
Web 	GET discourse.ubuntu.com/t/ubuntu-25-04-sddm-login-on-dual-monitor/67638
...
Traceback (innermost first)

    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in rescue in establish_connection
              raise CannotConnectError, "Error connecting to Redis on #{location} (#{error.class})"...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in establish_connection
            def establish_connection...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in block in connect
                establish_connection...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in with_reconnect
              yield...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in connect
              with_reconnect(false) do...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in ensure_connected
                connect unless connected?...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in block in process
                ensure_connected do...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in logging
              return yield unless @logger&.debug?...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in process
              logging(commands) do...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/client.rb: in call
              reply = process([command]) { read }...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-mini-profiler-3.3.1/lib/mini_profiler/profiling_methods.rb: in block in profile_method
                  return self.send without_profiling, *args, &orig unless Rack::MiniProfiler.current...
    (eval): in call
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis.rb: in block in send_command
              @client.call(command, &block)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis.rb: in synchronize
            @monitor.synchronize do...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis.rb: in send_command
            @monitor.synchronize do...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/redis-4.8.1/lib/redis/commands/lists.rb: in llen
                send_command([:llen, key])...
    /srv/discourse/app/lib/rate_limiter.rb: in is_under_limit?
            (redis.llen(prefixed_key) < @max) ||...
    /srv/discourse/app/lib/rate_limiter.rb: in can_perform?
            rate_unlimited? || is_under_limit?...
    /srv/discourse/app/lib/middleware/request_tracker.rb: in rate_limit
            if !limiter_assets10.can_perform?...
    /srv/discourse/app/lib/middleware/request_tracker.rb: in call
            if error_details = rate_limit(request, cookie)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/remote_ip.rb: in call
              @app.call(req.env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/railties-7.1.3.4/lib/rails/engine.rb: in call
              app.call req.env...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/railties-7.1.3.4/lib/rails/railtie.rb: in public_send
                    instance.public_send(name, *args, &block)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/railties-7.1.3.4/lib/rails/railtie.rb: in method_missing
                    instance.public_send(name, *args, &block)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/urlmap.rb: in block in call
                return app.call(env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/urlmap.rb: in each
              @mapping.each do |host, location, match, app|...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/urlmap.rb: in call
              @mapping.each do |host, location, match, app|...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/tempfile_reaper.rb: in call
              status, headers, body = @app.call(env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/lint.rb: in _call
              ary = @app.call(env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/lint.rb: in call
              dup._call(env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/show_exceptions.rb: in call
              @app.call(env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/common_logger.rb: in call
              status, headers, body = @app.call(env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/chunked.rb: in call
              status, headers, body = @app.call(env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/rack-2.2.9/lib/rack/content_length.rb: in call
              status, headers, body = @app.call(env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb: in process_client
            status, headers, body = @app.call(env)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb: in worker_loop
                  process_client(client)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb: in spawn_missing_workers
                worker_loop(worker)...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb: in maintain_worker_count
            off < 0 and return spawn_missing_workers...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb: in join
                maintain_worker_count if respawn...
    /srv/discourse/app/vendor/bundle/ruby/3.2.0/gems/unicorn-6.1.0/bin/unicorn: in <top (required)>
        Unicorn::HttpServer.new(app, options).start.join...
    /srv/discourse/app/bin/unicorn: in load
          load Gem.bin_path('unicorn', 'unicorn')...
    /srv/discourse/app/bin/unicorn: in <main>
          load Gem.bin_path('unicorn', 'unicorn')...

Request information
GET

No GET data.
POST

No POST data.
COOKIES
Variable 	Value
_cookies_accepted 	
"all"
_t 	
...

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions