Credentials can leak via inspect, error messages, and VCR cassettes #2

Open
opened 2026-09-30 20:52:35 +00:00 by jared · 0 comments
Owner

Discovered

This gem can expose its credential through three paths. A generator audit of the api-wrapper template found the same pattern here.

  • Credential members: api_key, username, password (held in a Data.define Configuration, so inspect, to_h, and deconstruct_keys print them; Client and Connection also hold the raw value in an ivar).
  • Auth scheme: Bearer (plus username/password members).
  • Error echo: Message construction at lib/simplefin_api/errors.rb:83 echoes server text. Error objects also keep the raw parsed body, so an echoed credential survives in err.body. Echo site: lib/simplefin_api/errors.rb:83.
  • VCR: VCR filter present; check it covers the actual scheme and all three members.

Correct fix

Bring the gem onto the fixed api-wrapper tier1 design. Do not make ad-hoc edits.

  • Adopt the Secret value object for every credential member (api_key, username, password). inspect and to_s return [REDACTED]. The raw value is read only at request dispatch. Configuration#inspect, #to_h, and #deconstruct_keys never expose it.
  • Error messages contain the HTTP status and error code only. err.body is scrubbed of the configured secret.
  • VCR filter keyed to this gem's actual scheme (Bearer (plus username/password members)) for the header value, plus the API host.
  • The client must not hold the raw key in an ivar.

Task checklist

  • Wait for, then pull, the cc-plugins #78 and #76 template versions.
  • Add a regression test: the fake credential is absent from client.inspect, configuration.inspect, to_h, and every error message for stubbed 401/403/404/422/500 bodies that echo it. A stubbed request asserts the raw fake credential reaches the wire.
  • Adopt Secret and Configuration coercion.
  • Fix error message construction at lib/simplefin_api/errors.rb:83 (and other echo sites) and scrub err.body.
  • Add VCR filters for the scheme and the host.
  • Audit existing cassettes AND git history (git log -p -- test/ and the cassette dirs) for real credential values. If any are found, rotate the credential and purge or re-record.
  • Align with #75 (rename test_client) and, if the gem defines operations named run/raw/paginate/unwrap/connection/scope, with #77. Resource Base defines unwrap, raw, paginate, run (lib/simplefin_api/resources/base.rb:42,49,65,74).

Acceptance criteria

  1. The regression test passes.
  2. grep of the cassettes finds no credential and no real host.
  3. The full suite is green.

Upstream


Discoverer: /home/jared/dev/cc-plugins, session 37920212-7933-486a-9506-c241c150dd1f, 2026-09-30. Audit of generated gems found credential-leak paths from the api-wrapper template.

## Discovered This gem can expose its credential through three paths. A generator audit of the api-wrapper template found the same pattern here. - Credential members: api_key, username, password (held in a `Data.define` Configuration, so `inspect`, `to_h`, and `deconstruct_keys` print them; Client and Connection also hold the raw value in an ivar). - Auth scheme: Bearer (plus username/password members). - Error echo: Message construction at lib/simplefin_api/errors.rb:83 echoes server text. Error objects also keep the raw parsed `body`, so an echoed credential survives in `err.body`. Echo site: lib/simplefin_api/errors.rb:83. - VCR: VCR filter present; check it covers the actual scheme and all three members. ## Correct fix Bring the gem onto the fixed api-wrapper tier1 design. Do not make ad-hoc edits. - Adopt the `Secret` value object for every credential member (api_key, username, password). `inspect` and `to_s` return `[REDACTED]`. The raw value is read only at request dispatch. `Configuration#inspect`, `#to_h`, and `#deconstruct_keys` never expose it. - Error messages contain the HTTP status and error code only. `err.body` is scrubbed of the configured secret. - VCR filter keyed to this gem's actual scheme (Bearer (plus username/password members)) for the header value, plus the API host. - The client must not hold the raw key in an ivar. ## Task checklist - [ ] Wait for, then pull, the cc-plugins #78 and #76 template versions. - [ ] Add a regression test: the fake credential is absent from `client.inspect`, `configuration.inspect`, `to_h`, and every error message for stubbed 401/403/404/422/500 bodies that echo it. A stubbed request asserts the raw fake credential reaches the wire. - [ ] Adopt `Secret` and Configuration coercion. - [ ] Fix error message construction at lib/simplefin_api/errors.rb:83 (and other echo sites) and scrub `err.body`. - [ ] Add VCR filters for the scheme and the host. - [ ] Audit existing cassettes AND git history (`git log -p -- test/` and the cassette dirs) for real credential values. If any are found, rotate the credential and purge or re-record. - [ ] Align with #75 (rename `test_client`) and, if the gem defines operations named run/raw/paginate/unwrap/connection/scope, with #77. Resource Base defines `unwrap`, `raw`, `paginate`, `run` (lib/simplefin_api/resources/base.rb:42,49,65,74). ## Acceptance criteria 1. The regression test passes. 2. `grep` of the cassettes finds no credential and no real host. 3. The full suite is green. ## Upstream - https://github.com/jaredswanson/cc-plugins/issues/78 (credential redaction) - https://github.com/jaredswanson/cc-plugins/issues/76 (VCR filter for any auth scheme and host) - https://github.com/jaredswanson/cc-plugins/issues/75 (test_client helper runs as a test) - https://github.com/jaredswanson/cc-plugins/issues/77 (Base helpers run/raw collide with operation names) -------- **Discoverer:** /home/jared/dev/cc-plugins, session 37920212-7933-486a-9506-c241c150dd1f, 2026-09-30. Audit of generated gems found credential-leak paths from the api-wrapper template.
Sign in to join this conversation.
No description provided.