Skip to content

Fix/secretnav#136

Closed
jakehulberg wants to merge 3 commits into
Infisical:mainfrom
jelrod27:fix/secretnav
Closed

Fix/secretnav#136
jakehulberg wants to merge 3 commits into
Infisical:mainfrom
jelrod27:fix/secretnav

Conversation

@jakehulberg
Copy link
Copy Markdown

Description 📣

Type ✨

  • Bug fix
  • New feature
  • Improvement
  • Breaking change
  • Documentation

Tests 🛠️

# Here's some code block to paste some code snippets

jelrod27 and others added 3 commits February 25, 2026 10:28
Adds a new `infisical tui` command that launches an interactive terminal
UI powered by Bubble Tea and Gemini AI. Users can manage secrets via
natural language prompts instead of memorizing CLI flags.

Features:
- AI prompt bar (Gemini 3.1) for NL -> CLI command translation
- Secret browser with keyboard navigation and search/filter
- Secret detail view with reveal/mask toggle
- Create, update, and delete secrets
- Environment switcher (dev/staging/prod)
- Command preview with safety confirmation for destructive ops
- Production environment warning banners
- Help modal with keyboard shortcut reference
- Auth detection and setup guidance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…dit log

Secret values are now redacted before reaching the Gemini API via a
sanitize → placeholder → hydrate pipeline. Commands are validated against
an allowlist and checked for shell injection before execution. All AI-
generated commands are logged to ~/.itui/audit.log. Adds standalone
`itui` binary entry point (cmd/itui/main.go).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jakehulberg jakehulberg deleted the fix/secretnav branch February 25, 2026 14:47
@jakehulberg jakehulberg restored the fix/secretnav branch February 25, 2026 14:48
@jakehulberg jakehulberg deleted the fix/secretnav branch February 25, 2026 14:50
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Feb 25, 2026

Greptile Summary

This PR adds ITUI (Infisical Terminal UI), an AI-powered terminal interface that uses Google Gemini to translate natural language prompts into Infisical CLI commands. The feature includes a Bubble Tea-based TUI with secret browsing, environment switching, AI prompt bar, and command execution with an audit log.

  • Compiled binaries committed: Two ~83MB compiled binaries (infisical and itui) are checked into the repository. These must be removed and added to .gitignore before merging.
  • Command injection in secret form: The SecretCreatedMsg handler in itui.go:242 interpolates user-provided key/value directly into a command string via fmt.Sprintf without escaping. Values with spaces or flag-like content will produce malformed or unintended commands.
  • run command in allowlist: The run subcommand allows arbitrary command execution after -- (e.g., infisical run -- rm -rf /). The AI could be prompt-injected into generating dangerous run commands that pass validation.
  • Silent error swallowing in AI client: NewAIClient discards the error from genai.NewClient and returns a partially-initialized struct, making initialization failures hard to debug.
  • No user-facing documentation: No docs were found for this new infisical tui command. How will customers discover this feature?

Confidence Score: 1/5

  • This PR has critical issues (committed binaries, command injection, unsafe allowlist) that must be resolved before merging.
  • Score of 1 reflects: (1) two ~83MB compiled binaries committed to the repo that will permanently bloat Git history, (2) a command injection vulnerability where form input is interpolated unsanitized into CLI commands, (3) the run subcommand in the security allowlist enabling arbitrary command execution via AI prompt injection, and (4) silent error swallowing in AI client initialization.
  • Pay close attention to infisical and itui (binaries that must be removed), packages/itui/itui.go (command injection in SecretCreatedMsg handler), and packages/itui/security.go (run in the allowlist).

Important Files Changed

Filename Overview
infisical Compiled binary (~83MB) accidentally committed to version control. Must be removed and added to .gitignore.
itui Compiled binary (~83MB) accidentally committed to version control. Must be removed and added to .gitignore.
packages/itui/itui.go Main TUI orchestration. Command injection vulnerability in SecretCreatedMsg handler where user input is interpolated without escaping into command strings.
packages/itui/security.go Command validation allowlist includes run subcommand which enables arbitrary command execution after -- separator.
packages/itui/ai.go AI client wrapper for Gemini API. Silently swallows client initialization errors, returning a broken client instance.
packages/itui/executor.go Command executor with validation. Uses exec.Command (not shell) which is good for security. Double-validates commands (in executeCommand and RunRaw).
packages/itui/sanitizer.go Value sanitization for AI prompts. Regexes are recompiled on each call unnecessarily. Core sanitization logic is sound.
.gitignore Removed /agent-testing, added .claude/worktrees/. Missing entries for compiled binaries infisical and itui.
packages/itui/components/secretform.go Secret creation form component. No input validation on key/value before emitting SecretCreatedMsg.
go.mod Added bubbletea, bubbles, genai dependencies. Updated lipgloss from v0.9.1 to v1.1.0 (major version bump).

Last reviewed commit: 128ffd8

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

31 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

Comment thread packages/itui/itui.go
Comment on lines +240 to +244
case components.SecretCreatedMsg:
return m, m.executeCommand(
fmt.Sprintf("infisical secrets set %s=%s --env=%s --path=%s",
msg.Key, msg.Value, m.ctx.Environment, m.ctx.Path),
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Command injection via unsanitized form input

User-provided msg.Key and msg.Value are directly interpolated into a command string via fmt.Sprintf without any escaping or quoting. A secret value containing spaces (e.g., hello world) would be split into separate arguments by splitArgs, truncating the value. More critically, a value like foo --env=prod would inject additional flags, potentially targeting a different environment than intended.

Since the executor uses exec.Command (not a shell), shell metacharacters aren't directly exploitable, but argument injection is. The value should be passed as a properly quoted argument, or better yet, the Executor.Run method should be called directly with properly separated arguments instead of constructing a raw command string:

Suggested change
case components.SecretCreatedMsg:
return m, m.executeCommand(
fmt.Sprintf("infisical secrets set %s=%s --env=%s --path=%s",
msg.Key, msg.Value, m.ctx.Environment, m.ctx.Path),
)
case components.SecretCreatedMsg:
return m, m.executeCommand(
fmt.Sprintf("infisical secrets set %s='%s' --env=%s --path=%s",
msg.Key, strings.ReplaceAll(msg.Value, "'", "'\\''"), m.ctx.Environment, m.ctx.Path),
)

Comment thread packages/itui/security.go
"secrets delete": true,
"secrets folders": true,
"export": true,
"run": true,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

run subcommand in allowlist enables arbitrary command execution

The run command passes everything after -- to the system as a subprocess (e.g., infisical run --env=dev -- rm -rf /). Since ValidateCommand only checks the subcommand prefix and shell metacharacters, but not the payload after --, the AI model could be prompt-injected into generating a run command with an arbitrary and dangerous subprocess.

Consider either:

  1. Removing run from the allowlist entirely, or
  2. Adding validation that specifically inspects and restricts what comes after -- in run commands

Comment thread packages/itui/ai.go
Comment on lines +19 to +31
func NewAIClient(apiKey string) *AIClient {
client, err := genai.NewClient(context.Background(), &genai.ClientConfig{
APIKey: apiKey,
Backend: genai.BackendGeminiAPI,
})
if err != nil {
return &AIClient{model: "gemini-2.5-flash"}
}

return &AIClient{
client: client,
model: "gemini-2.5-flash",
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Silent error swallowing returns broken client

When genai.NewClient fails, the error is silently discarded and a &AIClient{model: "gemini-2.5-flash"} is returned with a nil client field. The caller (NewModel in itui.go) stores this and only discovers the problem later when Translate is called. This makes debugging harder — the user won't know their API key is invalid or that the client failed to initialize.

Consider returning the error or logging a warning so the user knows initialization failed:

func NewAIClient(apiKey string) (*AIClient, error) {
    client, err := genai.NewClient(context.Background(), &genai.ClientConfig{
        APIKey:  apiKey,
        Backend: genai.BackendGeminiAPI,
    })
    if err != nil {
        return nil, fmt.Errorf("failed to create AI client: %w", err)
    }
    return &AIClient{client: client, model: "gemini-2.5-flash"}, nil
}

Comment thread packages/itui/itui.go
Comment on lines +286 to +289
if item, ok := m.secretBrowser.SelectedItem(); ok {
isProd := strings.EqualFold(m.ctx.Environment, "prod") || strings.EqualFold(m.ctx.Environment, "production")
cmd := fmt.Sprintf("infisical secrets delete %s --env=%s --path=%s --type=shared", item.KeyName, m.ctx.Environment, m.ctx.Path)
m.confirmDialog.Show(cmd, fmt.Sprintf("Delete secret '%s' from %s?", item.KeyName, m.ctx.Environment), true, isProd)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Delete command also vulnerable to argument injection

Similar to the SecretCreatedMsg handler, item.KeyName is interpolated directly into the command string. If a secret key name contains spaces or flag-like patterns (unlikely but possible depending on the backend), this could produce malformed or unintended commands. Consider using the Executor.Run method directly with properly separated args for all programmatically-constructed commands.

Comment on lines +51 to +53
if isWriteOp {
// Look for "to VALUE" pattern (most common)
toPattern := regexp.MustCompile(`(?i)\bto\s+(\S+(?:\S*://\S+|\S+))`)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Regex compiled inside function on every call

toPattern and eqPattern are compiled with regexp.MustCompile inside SanitizePrompt, meaning they are re-compiled every time the function is called. Since these are static patterns, they should be compiled once as package-level variables (similar to valuePatterns at the top of the file) for better performance.

Suggested change
if isWriteOp {
// Look for "to VALUE" pattern (most common)
toPattern := regexp.MustCompile(`(?i)\bto\s+(\S+(?:\S*://\S+|\S+))`)
if isWriteOp {
// Look for "to VALUE" pattern (most common)
if matches := writeToPattern.FindStringSubmatchIndex(sanitized); matches != nil {

Where writeToPattern and writeEqPattern are declared as package-level vars alongside valuePatterns.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Feb 25, 2026

Additional Comments (1)

infisical
Compiled binaries committed to repo

Two compiled binary files (infisical at ~83MB and itui at ~83MB) have been committed to the repository. These should not be checked into version control — they bloat the repo permanently (even after deletion, Git retains them in history), make diffs unreadable, and are platform-specific. Add infisical and itui to .gitignore and remove them from tracking.

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.

2 participants