Security: no automated grep or test fixture confirms indexer logs avoid secrets [SEC-F13] #433

Closed
opened 2026-06-29 15:37:43 +00:00 by totdking · 13 comments
totdking commented 2026-06-29 15:37:43 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-06-29 15:38:58 +00:00 (Migrated from gitlab.com)

Summary

indexer/src/main.rs emits four tracing::info! calls at startup (lines 108-115): run_mode, lcd_urls, factory_address, and rate limit values. The database_url (a postgres://user:password@host/db connection string) is consumed only by sqlx::PgPoolOptions::connect at line 119 and is not logged. Grep across all indexer/src/ files finds no tracing::info! call emitting database_url, password, mnemonic, bearer, private_key, or secret. However, no Makefile target, CI step, or test fixture enforces this automatically. No ongoing check prevents a future change from accidentally introducing a secret log line.


What Was Checked

  • indexer/src/main.rs lines 108-115: four startup log calls. Values logged: config.run_mode, config.lcd_urls, config.factory_address, config.rate_limit_rps, config.rate_limit_lcd_heavy_rps. None of these are secrets.
  • indexer/src/main.rs line 119: connect(&config.database_url) -- DATABASE_URL used for connection but not logged.
  • Grep across indexer/src/ for database_url, password, mnemonic, bearer, private_key, secret inside any tracing:: call: zero matches. Confirmed by grep with no output.
  • Makefile: no lint-log-secrets target or equivalent CI step found. Grep for "DATABASE_URL" in Makefile returned no output.

Expected (per checklist)

A grep/static review must be documented (in Makefile, CI config, or runbook) confirming no secret patterns appear in log call arguments. Where feasible, a test fixture initializes the indexer with a test DATABASE_URL and captures log output, asserting the password component is absent.


Actual

The current source does not log secrets. This was confirmed by manual grep during this audit session. There is no automated check or test fixture to enforce this going forward. If a future change adds a tracing::info!("{}", config.database_url) line, no CI job will catch it.


Evidence

  • indexer/src/main.rs lines 108-115: logged fields are run_mode, lcd_urls, factory_address, rate_limit_rps, rate_limit_lcd_heavy_rps -- no secrets
  • indexer/src/main.rs line 119: config.database_url used in connect() only, not logged
  • Grep of indexer/src/ for secret-pattern log calls: zero matches
  • Makefile: no lint-log-secrets or secret-scanning target found

Suggested Fix

Add a make lint-log-secrets Makefile target that greps indexer/src/ for patterns such as database_url, password, mnemonic, bearer, private_key inside tracing:: macro arguments, and exits nonzero if any match is found. Optionally add a test in indexer/tests/security.rs that initializes a config with a DATABASE_URL containing a dummy password string and asserts the tracing output does not contain that password.


Verification Checklist

  • A Makefile target or CI step greps indexer source for secret-pattern log calls and exits nonzero on match
  • Or: a test captures startup log output and asserts DATABASE_URL password is not present
  • Or: a runbook step documents the manual grep procedure and its last confirmed date

Labels

security, pre-launch

Cc: @PlasticDigits

### Summary `indexer/src/main.rs` emits four `tracing::info!` calls at startup (lines 108-115): `run_mode`, `lcd_urls`, `factory_address`, and rate limit values. The `database_url` (a `postgres://user:password@host/db` connection string) is consumed only by `sqlx::PgPoolOptions::connect` at line 119 and is not logged. Grep across all `indexer/src/` files finds no `tracing::info!` call emitting `database_url`, `password`, `mnemonic`, `bearer`, `private_key`, or `secret`. However, no Makefile target, CI step, or test fixture enforces this automatically. No ongoing check prevents a future change from accidentally introducing a secret log line. --- ### What Was Checked - `indexer/src/main.rs` lines 108-115: four startup log calls. Values logged: `config.run_mode`, `config.lcd_urls`, `config.factory_address`, `config.rate_limit_rps`, `config.rate_limit_lcd_heavy_rps`. None of these are secrets. - `indexer/src/main.rs` line 119: `connect(&config.database_url)` -- DATABASE_URL used for connection but not logged. - Grep across `indexer/src/` for `database_url`, `password`, `mnemonic`, `bearer`, `private_key`, `secret` inside any `tracing::` call: zero matches. Confirmed by grep with no output. - Makefile: no `lint-log-secrets` target or equivalent CI step found. Grep for "DATABASE_URL" in Makefile returned no output. --- ### Expected (per checklist) A grep/static review must be documented (in Makefile, CI config, or runbook) confirming no secret patterns appear in log call arguments. Where feasible, a test fixture initializes the indexer with a test DATABASE_URL and captures log output, asserting the password component is absent. --- ### Actual The current source does not log secrets. This was confirmed by manual grep during this audit session. There is no automated check or test fixture to enforce this going forward. If a future change adds a `tracing::info!("{}", config.database_url)` line, no CI job will catch it. --- ### Evidence - `indexer/src/main.rs` lines 108-115: logged fields are `run_mode`, `lcd_urls`, `factory_address`, `rate_limit_rps`, `rate_limit_lcd_heavy_rps` -- no secrets - `indexer/src/main.rs` line 119: `config.database_url` used in `connect()` only, not logged - Grep of `indexer/src/` for secret-pattern log calls: zero matches - Makefile: no `lint-log-secrets` or secret-scanning target found --- ### Suggested Fix Add a `make lint-log-secrets` Makefile target that greps `indexer/src/` for patterns such as `database_url`, `password`, `mnemonic`, `bearer`, `private_key` inside `tracing::` macro arguments, and exits nonzero if any match is found. Optionally add a test in `indexer/tests/security.rs` that initializes a config with a DATABASE_URL containing a dummy password string and asserts the tracing output does not contain that password. --- ### Verification Checklist - [ ] A Makefile target or CI step greps indexer source for secret-pattern log calls and exits nonzero on match - [ ] Or: a test captures startup log output and asserts DATABASE_URL password is not present - [ ] Or: a runbook step documents the manual grep procedure and its last confirmed date --- ### Labels `security`, `pre-launch` Cc: @PlasticDigits
totdking commented 2026-06-29 15:39:07 +00:00 (Migrated from gitlab.com)

mentioned in issue #381

mentioned in issue #381
Brouie commented 2026-06-29 15:53:39 +00:00 (Migrated from gitlab.com)

mentioned in merge request !961

mentioned in merge request !961
Brouie commented 2026-06-29 15:54:11 +00:00 (Migrated from gitlab.com)

Took this one — current state is clean, and I added the automated guard the checklist asks for (MR !961).

Verified current state two ways:

  • Source: the only startup logging is main.rs lines 108-115 (run_mode, lcd_urls, factory_address, rate limits); database_url is used at connect() (line 119) and never logged. Grep across indexer/src for a secret-pattern value inside any tracing/log/print macro: zero (the only "token" hits are trading-token volume refreshes, not auth tokens).
  • Runtime: scanned the live indexer log (~15h, 511MB) — zero postgres:// connection strings, and the DB password literal appears zero times. Nothing is leaking now.

The guard (MR !961):

  • scripts/check_indexer_log_secrets.py + a make lint-log-secrets target, wired into make lint. It scans indexer/src for log/print macros emitting secret-bearing identifiers (database_url, password, mnemonic, private_key, bearer, api_key, secret, credential, ...) AND for the whole Config struct being logged via Debug. That second case matters: Config derives Debug and holds database_url, so a {:?} on the whole struct would leak the password even without the word "database_url" on the line. Exits nonzero on a match; a proven-safe line can opt out with a trailing // log-secrets-ok.
  • Adversarially tested: planting tracing::info!("{}", config.database_url) and tracing::debug!("{:?}", config) are both caught; benign config.rate_limit_rps, a trading ask_token, and the opt-out marker are correctly ignored. Passes clean on current main.

Covers the checklist's first item (a make/CI target that greps indexer source for secret-pattern log calls and exits nonzero on match). Good to close from my side once !961 merges. @PlasticDigits

Took this one — current state is clean, and I added the automated guard the checklist asks for (MR !961). Verified current state two ways: - Source: the only startup logging is main.rs lines 108-115 (run_mode, lcd_urls, factory_address, rate limits); database_url is used at connect() (line 119) and never logged. Grep across indexer/src for a secret-pattern value inside any tracing/log/print macro: zero (the only "token" hits are trading-token volume refreshes, not auth tokens). - Runtime: scanned the live indexer log (~15h, 511MB) — zero postgres:// connection strings, and the DB password literal appears zero times. Nothing is leaking now. The guard (MR !961): - scripts/check_indexer_log_secrets.py + a make lint-log-secrets target, wired into make lint. It scans indexer/src for log/print macros emitting secret-bearing identifiers (database_url, password, mnemonic, private_key, bearer, api_key, secret, credential, ...) AND for the whole Config struct being logged via Debug. That second case matters: Config derives Debug and holds database_url, so a {:?} on the whole struct would leak the password even without the word "database_url" on the line. Exits nonzero on a match; a proven-safe line can opt out with a trailing // log-secrets-ok. - Adversarially tested: planting tracing::info!("{}", config.database_url) and tracing::debug!("{:?}", config) are both caught; benign config.rate_limit_rps, a trading ask_token, and the opt-out marker are correctly ignored. Passes clean on current main. Covers the checklist's first item (a make/CI target that greps indexer source for secret-pattern log calls and exits nonzero on match). Good to close from my side once !961 merges. @PlasticDigits
PlasticDigits commented 2026-06-29 15:59:15 +00:00 (Migrated from gitlab.com)

mentioned in merge request !962

mentioned in merge request !962
Brouie commented 2026-06-29 16:19:21 +00:00 (Migrated from gitlab.com)

mentioned in merge request !964

mentioned in merge request !964
PlasticDigits commented 2026-06-29 16:21:41 +00:00 (Migrated from gitlab.com)

mentioned in commit 6fda72dc41

mentioned in commit 6fda72dc41f9326c5644ee523aae1bda8a60a8f2
PlasticDigits commented 2026-06-29 16:25:16 +00:00 (Migrated from gitlab.com)

mentioned in commit 5448d21404

mentioned in commit 5448d214040cdad7f0a42fc859fce309f18e28df
PlasticDigits commented 2026-06-29 16:26:07 +00:00 (Migrated from gitlab.com)

mentioned in commit 131058d111

mentioned in commit 131058d111fdcae7f32be3d1ea9c52f8eded2e17
PlasticDigits commented 2026-06-30 02:15:14 +00:00 (Migrated from gitlab.com)

mentioned in commit 2a06048bc6

mentioned in commit 2a06048bc63903ada3ad17d492b737bac18b19d8
PlasticDigits commented 2026-06-30 02:19:35 +00:00 (Migrated from gitlab.com)

Verification — #433 (SEC-F13)

Verified on main @ 2a06048b (MR !961 merged). All checklist items PASS. Issue closed.

Checklist

Item Result How verified
Makefile target or CI step greps indexer source for secret-pattern log calls (exits nonzero on match) PASS make lint-log-secrets → OK: no secret-bearing values…; make lint-indexer-log-secrets → OK: no secret-pattern fields…. Both wired into make lint. CI job lint-indexer-log-secrets in .gitlab-ci.yml runs scripts/lint-indexer-log-secrets.sh on default branch and MRs touching indexer/**.
Test captures startup log output; DATABASE_URL password absent PASS cargo test --lib startup::tests — 2/2 passed (startup_logs_do_not_contain_database_password, startup_logs_do_not_contain_reorg_webhook_url).
Runbook documents manual grep procedure PASS docs/operator-secrets.md § Logs documents make lint-indexer-log-secrets, unit tests in startup.rs, and CI job. Cross-linked from docs/indexer-invariants.md and skills/AGENTS_INDEXER_API_LCD_SECURITY.md.

Additional checks

Check Result How verified
Current source does not log secrets PASS indexer/src/startup.rs logs only run_mode, lcd_urls, factory_address, rate limits; database_url used at connect() only (main.rs). Manual rg across indexer/src/ for secret patterns inside tracing:: macros: zero matches.
Adversarial guard catches violations PASS Temp probe with tracing::info!("{}", config.database_url) → make lint-log-secrets equivalent exits 1 with file:line finding.
LocalTerra / runtime log scan SKIP Not required for this issue; automated grep + unit tests satisfy acceptance criteria. Prior audit (issue comment) confirmed live logs clean.

Commands run

make lint-log-secrets
make lint-indexer-log-secrets
cd indexer && cargo test --lib startup::tests
rg 'tracing::(info|debug|warn|error|trace)!.*(database_url|password|mnemonic|bearer|private_key|secret)' indexer/src/
## Verification — #433 (SEC-F13) Verified on `main` @ `2a06048b` (MR !961 merged). **All checklist items PASS.** Issue closed. ### Checklist | Item | Result | How verified | |------|--------|--------------| | Makefile target or CI step greps indexer source for secret-pattern log calls (exits nonzero on match) | **PASS** | `make lint-log-secrets` → `OK: no secret-bearing values…`; `make lint-indexer-log-secrets` → `OK: no secret-pattern fields…`. Both wired into `make lint`. CI job `lint-indexer-log-secrets` in `.gitlab-ci.yml` runs `scripts/lint-indexer-log-secrets.sh` on default branch and MRs touching `indexer/**`. | | Test captures startup log output; DATABASE_URL password absent | **PASS** | `cargo test --lib startup::tests` — 2/2 passed (`startup_logs_do_not_contain_database_password`, `startup_logs_do_not_contain_reorg_webhook_url`). | | Runbook documents manual grep procedure | **PASS** | `docs/operator-secrets.md` § Logs documents `make lint-indexer-log-secrets`, unit tests in `startup.rs`, and CI job. Cross-linked from `docs/indexer-invariants.md` and `skills/AGENTS_INDEXER_API_LCD_SECURITY.md`. | ### Additional checks | Check | Result | How verified | |-------|--------|--------------| | Current source does not log secrets | **PASS** | `indexer/src/startup.rs` logs only `run_mode`, `lcd_urls`, `factory_address`, rate limits; `database_url` used at `connect()` only (`main.rs`). Manual `rg` across `indexer/src/` for secret patterns inside `tracing::` macros: zero matches. | | Adversarial guard catches violations | **PASS** | Temp probe with `tracing::info!("{}", config.database_url)` → `make lint-log-secrets` equivalent exits 1 with file:line finding. | | LocalTerra / runtime log scan | **SKIP** | Not required for this issue; automated grep + unit tests satisfy acceptance criteria. Prior audit (issue comment) confirmed live logs clean. | ### Commands run ```bash make lint-log-secrets make lint-indexer-log-secrets cd indexer && cargo test --lib startup::tests rg 'tracing::(info|debug|warn|error|trace)!.*(database_url|password|mnemonic|bearer|private_key|secret)' indexer/src/ ```
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-30 02:19:36 +00:00
Brouie commented 2026-06-30 03:15:16 +00:00 (Migrated from gitlab.com)

mentioned in issue #337

mentioned in issue #337
PlasticDigits commented 2026-08-22 10:59:15 +00:00 (Migrated from gitlab.com)

mentioned in issue #594

mentioned in issue #594
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#433
No description provided.