basecamp / basecamp/once-campfire
Bot key is still written to the log in the clear — Thruster's access log isn't covered by #269
- Dominant language
- Ruby
- Stars
- 4.6k
- Forks
- 791
- Avg merge
- 11h 8m
- Merged PRs (30d)
- 13
Description
#269 added `LogScrubbingFormatter` and wired it into `config.logger`, which redacts the bot-key path segment out of Rails' log lines. But Rails isn't the only thing logging the request path in that container.
`Procfile` runs the web process as `web: bundle exec thrust bin/start-app`, so Thruster fronts Rails and writes its own JSON access log to the same stdout. That log is untouched by a Rails log formatter, and it contains the full path:
```json
{"time":"2026-09-09T18:23:28.032553851Z","level":"INFO","msg":"Request",
"path":"/rooms/2//messages","status":201,"dur":287,
"method":"POST","req_content_length":178,"req_content_type":"text/html; charset=utf-8",
"resp_content_length":20,"resp_content_type":"application/json",
"remote_addr":"172.18.0.1:39662","user_agent":"Ruby","cache":"bypass",
"query":"","proto":"HTTP/1.1"}
```
Same request, both loggers, on a node running `ef147d1`:
```
$ docker logs campfire | grep -cE '/rooms/[0-9]+/\[FILTERED\]' # Rails, redacted
1
$ docker logs campfire | grep -cE '/rooms/[0-9]+/[0-9]+-[A-Za-z0-9]{6,}' # Thruster, in the clear
2
```
**Why it matters:** the bot key is the entire credential for that room — anyone holding the URL can post as the bot, and there's no separate auth header to rotate independently. Container logs are routinely shipped to a log aggregator, read by anyone with `docker logs` access, and retained long after the request. In our deployment the alert relay posts through the bot API, so every alert delivery writes a live credential into the log; the only reason it's contained is that nothing ships that node's logs.
**Reproduce:** POST to a bot endpoint on a production-mode container and read the container log — the Rails `Started POST` line is redacted, the Thruster `"msg":"Request"` line above it is not.
**Possible directions** (I don't have a view on which you'd prefer):
1. Redact the path in Thruster itself — it's basecamp/thruster, and a path-redaction pattern would help any app that puts a secret in a path segment.
2. Take the key out of the URL path — accept it as a header (or a query parameter, which `filter_parameters` already covers), keeping the path form as a deprecated alias.
3. Document it, so operators know `docker logs` on a Campfire container is secret-bearing and shouldn't be shipped.
Happy to send a PR for whichever direction you'd take.
Versions: once-campfire `ef147d1`, image `ghcr.io/basecamp/once-campfire@sha256:d5e55bd8eb56…`, thruster 0.1.23.
Contributor guide
Research direction
The issue names Procfile, LogScrubbingFormatter, config.logger, and Thruster 0.1.23; start by reproducing the POST in a production-mode container and comparing docker logs for Rails and Thruster entries. Done means the bot key is not exposed in either access log, with the chosen direction and any compatibility or documentation impact settled.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, rails, ruby
- Domain
- backend, observability, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100