Skip to content

[codex] fix codex security scan findings#49

Merged
baanish merged 2 commits into
masterfrom
codex/security-scan-fixes
Jul 2, 2026
Merged

[codex] fix codex security scan findings#49
baanish merged 2 commits into
masterfrom
codex/security-scan-fixes

Conversation

@baanish

@baanish baanish commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • escape terminal control characters in AI command previews and project metadata display
  • remove the default AI fallback and block cross-endpoint fallback unless explicitly opted in
  • use no-echo prompting for interactive API-key entry on TTYs
  • update agent notes for the new fallback behavior

History scrub

  • Rewrote visible GitHub heads and tags to remove .meowcode.json from history.
  • Verified local visible refs now return zero .meowcode.json path/object hits.
  • GitHub rejected hidden refs/pull/* updates during mirror push; those refs are not writable via Git push and may require GitHub-side cleanup if they still expose old objects.

Validation

  • cargo test
  • cargo fmt --all -- --check
  • cargo clippy --all-targets --locked -- -D warnings
  • cargo build --locked --verbose
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Sensitive setup prompts now hide API keys during input when using an interactive terminal.
    • Command suggestions and project selection text now safely display special characters.
  • Bug Fixes

    • Fallback AI requests are now blocked by default when they would switch to a different endpoint, unless explicitly allowed.
    • Paths and suggestion text are escaped before being shown in the terminal to prevent confusing or unsafe output.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@baanish, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 92f24eed-1c96-4db8-9009-018287a82cc7

📥 Commits

Reviewing files that changed from the base of the PR and between 6233baa and 61bec3a.

📒 Files selected for processing (2)
  • src/ai/client.rs
  • src/terminal.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/security-scan-fixes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@baanish baanish marked this pull request as ready for review July 2, 2026 09:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/ai/client.rs (1)

344-356: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Test doesn't guard against ambient QR_AI_ALLOW_CROSS_ENDPOINT_FALLBACK.

clear_test_env only clears API-key vars; it never unsets QR_AI_ALLOW_CROSS_ENDPOINT_FALLBACK. If that variable happens to be set in the shell/CI environment running the suite, fallback_can_receive_prompt would return true, the fallback server (which returns 200) would succeed, and .unwrap_err() at line 490 would panic instead of asserting the refusal message.

🧪 Proposed fix to make the test hermetic
     fn clear_test_env() {
         for key in [
             "QR_TEST_AI_KEY",
             "CUSTOM_QR_TEST_AI_KEY",
             "CUSTOM_QR_TEST_ANTHROPIC_KEY",
             "OPENAI_API_KEY",
             "ANTHROPIC_API_KEY",
+            "QR_AI_ALLOW_CROSS_ENDPOINT_FALLBACK",
         ] {
             unsafe {
                 std::env::remove_var(key);
             }
         }
     }

Also applies to: 458-501

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ai/client.rs` around lines 344 - 356, The test setup in clear_test_env is
not hermetic because it leaves QR_AI_ALLOW_CROSS_ENDPOINT_FALLBACK intact, which
can change fallback_can_receive_prompt and make the fallback assertion in
fallback_can_receive_prompt / the unwrap_err path fail unpredictably. Update
clear_test_env to also remove QR_AI_ALLOW_CROSS_ENDPOINT_FALLBACK so the tests
controlling cross-endpoint fallback behavior are isolated from ambient shell or
CI environment state.
🧹 Nitpick comments (1)
src/terminal.rs (1)

7-17: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider also escaping Unicode bidi/format control characters, not just C0/C1.

ch.is_control() only matches Unicode general category Cc (C0/C1 controls). It does not match category Cf format characters such as RLO/LRO/PDF (U+202A–U+202E) or the isolate controls (U+2066–U+2069). These can reorder/hide the visual rendering of a string in many terminals without any ANSI escape sequence — a Trojan-Source-style spoof — which defeats the stated goal of this function for the exact untrusted sources it's applied to (AI-generated command previews, git/filesystem-derived project names).

Since this utility is specifically meant to keep the preview "the user is meant to inspect" trustworthy, consider extending the filter to also escape Cf-category characters (or use a small allow-list of confirmed-safe scalar values instead of only excluding controls).

💡 Possible extension
 pub fn escape_untrusted(input: &str) -> String {
     let mut output = String::with_capacity(input.len());
     for ch in input.chars() {
-        if ch.is_control() {
+        if ch.is_control() || is_bidi_or_format_override(ch) {
             output.extend(ch.escape_default());
         } else {
             output.push(ch);
         }
     }
     output
 }
+
+fn is_bidi_or_format_override(ch: char) -> bool {
+    matches!(ch,
+        '\u{200B}'..='\u{200F}' | '\u{202A}'..='\u{202E}' | '\u{2066}'..='\u{2069}' | '\u{FEFF}'
+    )
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/terminal.rs` around lines 7 - 17, escape_untrusted currently only filters
ch.is_control(), so it misses Unicode format/bidi controls that can visually
reorder terminal text. Update escape_untrusted in terminal.rs to also escape or
reject Cf characters such as RLO/LRO/PDF and the isolate controls, using the
existing escape_default path or a small safe allow-list. Keep the behavior
centered on the escape_untrusted function so the preview remains trustworthy for
untrusted command and project-name input.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/ai/client.rs`:
- Around line 344-356: The test setup in clear_test_env is not hermetic because
it leaves QR_AI_ALLOW_CROSS_ENDPOINT_FALLBACK intact, which can change
fallback_can_receive_prompt and make the fallback assertion in
fallback_can_receive_prompt / the unwrap_err path fail unpredictably. Update
clear_test_env to also remove QR_AI_ALLOW_CROSS_ENDPOINT_FALLBACK so the tests
controlling cross-endpoint fallback behavior are isolated from ambient shell or
CI environment state.

---

Nitpick comments:
In `@src/terminal.rs`:
- Around line 7-17: escape_untrusted currently only filters ch.is_control(), so
it misses Unicode format/bidi controls that can visually reorder terminal text.
Update escape_untrusted in terminal.rs to also escape or reject Cf characters
such as RLO/LRO/PDF and the isolate controls, using the existing escape_default
path or a small safe allow-list. Keep the behavior centered on the
escape_untrusted function so the preview remains trustworthy for untrusted
command and project-name input.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bbe7fa18-daa2-4264-a46f-db69da335a11

📥 Commits

Reviewing files that changed from the base of the PR and between c1566d8 and 6233baa.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • AGENTS.md
  • Cargo.toml
  • config/default.toml
  • src/ai/client.rs
  • src/commands/do_cmd.rs
  • src/commands/go.rs
  • src/lib.rs
  • src/main.rs
  • src/terminal.rs
💤 Files with no reviewable changes (1)
  • config/default.toml

@kilo-code-bot

kilo-code-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • src/ai/client.rs
  • src/terminal.rs
Review Notes

Incremental review since 6233baa4. The change set adds test coverage for cross-endpoint fallback opt-in env cleanup in clear_test_env (registering ALLOW_CROSS_ENDPOINT_FALLBACK_ENV for removal and verifying it via a new test), and expands escape_untrusted in src/terminal.rs to also escape Unicode Cf (format-control) codepoints beyond the existing is_control() C0/C1 coverage. The new is_unicode_format_control set comprehensively covers bidi-override and invisible-character ranges (zero-width spaces, bidi embedding controls, BOM, interlinear annotations, tag characters, etc.), correctly neutralizing trojan-source / bidi-spoofing risks in project metadata and AI previews. Both new tests are internally consistent and follow existing patterns in the module.

Previous Review Summary (commit 6233baa)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 6233baa)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (9 files)
  • AGENTS.md
  • Cargo.toml
  • config/default.toml
  • src/ai/client.rs
  • src/commands/do_cmd.rs
  • src/commands/go.rs
  • src/lib.rs
  • src/main.rs
  • src/terminal.rs
Review Notes

Reviewed the security-hardening changes: new terminal::escape_untrusted (escapes C0/C1 control bytes via char::escape_default), its application across qr go labels/multi-match output, qr do inline previews and delegate suggestions, qr go cd path output; the cross-endpoint AI fallback guard (fallback_can_receive_prompt + same_ai_endpoint normalizing trailing slashes, gated by QR_AI_ALLOW_CROSS_ENDPOINT_FALLBACK); removal of the default [ai.fallback] block; and no-echo API-key entry on TTYs via rpassword. Logic, edge cases (EOF/empty-input handling in prompt_secret_required, protocol/URL-normalized endpoint comparison), and associated unit tests are consistent and correct. Cargo.lock excluded as a generated lockfile.


Reviewed by glm-5.2-short · Input: 12.2K · Output: 3.1K · Cached: 181.4K

@baanish baanish merged commit a5980d6 into master Jul 2, 2026
6 checks passed
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