Skip to content

Redaction: letter-only URL tokens and unpadded base64 secrets - #354

Merged
Minitour merged 3 commits into
fix/release-240-review-2from
fix/release-240-review-3
Oct 23, 2026
Merged

Minitour merged 3 commits into
fix/release-240-review-2from
fix/release-240-review-3

Conversation

@Minitour

Copy link
Copy Markdown
Member

Summary

Third round of Qodo follow-ups for the v2.4.0 release, on top of #353. Both comments on #353 were valid: two kinds of credentials still showed in the project API and UI.

Stacked on #353: merge this into fix/release-240-review-2 first, then #353 into fix/release-240-review, then #352 into develop.

What changed

  • Token-only URL userinfo (secret-redaction.ts): any userinfo of 16 or more characters without a password counts as a token, letters only included, so https://abcdefghijklmnop@host.example/repo is blanked. Short usernames like ssh://git@github.com stay visible.
  • Unpadded base64 secrets (secret-redaction.ts): base64-style values are now told apart from relative paths by Shannon entropy, as secret scanners do, instead of requiring +, = or exactly 40 characters. Path segments are words and score about 4 bits per character; random keys score 4.5 and up. The threshold is 4.3. + or = still count as a sure sign.

A blanked value is only hidden in the display. Saving the server keeps the stored value, so a false positive costs nothing beyond showing a blank field.

Test plan

  • Blanked: https://abcdefghijklmnop@host.example/repo and AbcdEFGH/ijkLMNO1234567890QRSTUV (both from the review), plus all earlier cases.
  • Still shown: ssh://git@github.com/org/repo.git, opt/ghidra11/support/analyzeHeadless, services/payments/api/v2/handlers, and the absolute and Windows paths.
  • bunx tsc --noEmit; the server suite has no assertion failures (only the known Windows EBUSY temp cleanup).

Checklist

  • Tests added or updated
  • bunx tsc --noEmit passes
  • Docs updated (if user-facing): not needed

🤖 Generated with Claude Code

Token-only URL userinfo counts at 16+ characters, letters only included.
Base64-style values are told apart from relative paths by Shannon
entropy instead of requiring + / = or exactly 40 characters.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Redact letter-only URL tokens and unpadded base64 secrets

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Blank URL userinfo tokens of at least 16 characters, including letter-only tokens.
• Detect unpadded base64-style secrets by entropy while preserving ordinary relative paths.
• Add regression cases for newly hidden credentials and paths that must remain visible.
Diagram

graph TD
  A["Project API"] --> B["Env redaction"] --> C{"Credential match?"} -->|No| D{"Base64 candidate?"} -->|Yes| E{"Marker or entropy?"} -->|Yes| F["Blank value"]
  C -->|Yes| F
  D -->|No| G["Keep value"]
  E -->|No| G
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Explicitly mark secret environment fields
  • ➕ Avoids entropy-based false positives for marked fields.
  • ➕ Makes redaction intent unambiguous.
  • ➖ Requires configuration or schema changes.
  • ➖ Unmarked credentials in existing configurations could remain visible.

Recommendation: Keep the value-based detection for this targeted fix: it protects existing configurations without requiring users to classify every field. Explicit secret metadata could complement it later, but would not by itself cover legacy, unmarked credentials.

Files changed (2) +24 / -7

Bug fix (1) +18 / -7
secret-redaction.tsRecognize more token-only URLs and unpadded base64 secrets +18/-7

Recognize more token-only URLs and unpadded base64 secrets

• Treats URL userinfo of at least 16 characters as credential-shaped even when it contains only letters. Replaces the exact-length fallback for base64-style values with a Shannon entropy threshold, retaining the existing marker checks.

src/server/secret-redaction.ts

Tests (1) +6 / -0
secret-redaction.test.tsCover newly redacted secrets and a preserved relative path +6/-0

Cover newly redacted secrets and a preserved relative path

• Adds assertions that a letter-only URL token and an unpadded base64-style value are blanked. Confirms that a service directory path remains visible alongside existing benign-value cases.

src/server/tests/secret-redaction.test.ts

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Some credentials appear in project data ✓ Resolved
Description
isBase64Secret replaces the previous 40-character mixed-case fallback with a 4.3-bit entropy
cutoff, leaving low-entropy credentials such as AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/a1B2
unredacted. When such a value is stored under a generic environment name, the project API returns it
unchanged because it has neither + nor = and the other value matchers do not recognize its
slash-containing form.
Code

src/server/secret-redaction.ts[74]

+	return /[+=]/.test(value) || shannonEntropy(value) >= 4.3;
Evidence
The example satisfies the Base64 shape and letter/digit checks but has neither a sure-sign character
nor enough character diversity for the new cutoff; the removed fallback matched its length and case.
A generic name bypasses name-based redaction, and the remaining generic value rule excludes
slash-containing strings, so the API redaction path leaves it intact.

src/server/secret-redaction.ts[51-61]
src/server/secret-redaction.ts[71-86]
src/server/secret-redaction.ts[100-134]
src/server/project-routes.ts[207-218]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The entropy cutoff exposes slash-containing, mixed-case 40-character credentials that the previous rule redacted.
## Fix Focus Areas
- src/server/secret-redaction.ts[71-86]
- src/server/__tests__/secret-redaction.test.ts[94-120]
## Recommended Fix
Retain the previous 40-character mixed-case check as an alternative to the entropy threshold, and add a regression test under a generic environment name.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. URL token regressions evade the new test ✓ Resolved
Description
The new LETTER_TOKEN_URL fixture contains TOKEN, so redactEnvValue blanks it through
SENSITIVE_ENV before evaluating the changed URL matcher. The assertion would still pass if the
letter-only userinfo regex stopped matching entirely, leaving this specific behavior untested.
Code

src/server/tests/secret-redaction.test.ts[104]

+				LETTER_TOKEN_URL: "https://abcdefghijklmnop@host.example/repo",
Evidence
The new fixture name matches the sensitive-name regex, and the early return prevents the changed
credential-value regex from being tested by this assertion.

src/server/tests/secret-redaction.test.ts[101-115]
src/server/secret-redaction.ts[43-57]
src/server/secret-redaction.ts[100-112]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The letter-only URL assertion passes through name-based redaction without exercising the URL matcher.
## Fix Focus Areas
- src/server/__tests__/secret-redaction.test.ts[101-116]
## Recommended Fix
Rename the fixture to a generic environment name that does not match `SENSITIVE_ENV`, and update the expected result accordingly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can reply 'qodo' on any finding to push back, ask questions, or dig deeper

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/server/secret-redaction.ts Outdated
Comment thread src/server/__tests__/secret-redaction.test.ts Outdated
The entropy check alone let low-entropy AWS-style keys through. The
fixtures named *_TOKEN / *_SECRET were blanked by name before the value
rules ran, so the tests did not cover them.
Redaction: keep the 40-character key rule, test value rules directly
@Minitour
Minitour merged commit 3278aa2 into fix/release-240-review-2 Oct 23, 2026
@Minitour Minitour mentioned this pull request Oct 23, 2026
8 of 9 tasks
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