Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ Download binaries from [GitHub Releases](https://github.com/Infisical/cli/releas
- **[Commands Reference](https://infisical.com/docs/cli/commands)** - All available commands
- **[FAQ](https://infisical.com/docs/cli/faq)** - Common questions and troubleshooting

## Shell Integration

To automatically run selected Zsh commands through `infisical run`, add this to your `.zshrc`:

```zsh
eval "$(infisical shell-init zsh)"
```

The integration wraps commands beginning with `npm`, `pnpm`, `bun`, or `node`.

## Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
Expand Down
48 changes: 48 additions & 0 deletions packages/cmd/shell_init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package cmd

import (
"fmt"

"github.com/spf13/cobra"
)

const zshShellInit = `# Infisical automatic command wrapper
if [[ -o interactive ]]; then
_infisical_auto_run_prefixes=(npm pnpm bun node)

_infisical_auto_run_accept_line() {
local command="${BUFFER%%[[:space:]]*}"
local prefix

for prefix in "${_infisical_auto_run_prefixes[@]}"; do
if [[ "$command" == "$prefix" ]]; then
BUFFER="infisical run -- $BUFFER"
Comment on lines +17 to +19

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.

P1 security Secrets reach dependency lifecycle scripts

When a user runs npm install, pnpm install, bun install, or a Node script in an untrusted project, this unconditional rewrite launches it through infisical run, and project-controlled code inherits the injected secrets and can exfiltrate them. How this was verified: The hook routes every matching command through the run path, which overlays fetched secrets onto the launched process environment.

Context Used: Flag SSRF risks (source)

Knowledge Base Used: infisical run Secret Injection Flow

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.

P1 Zsh command resolution is bypassed

When npm, pnpm, bun, or node is defined as a Zsh alias or function, forwarding the raw token through infisical run -- launches the PATH executable directly, causing the user's wrapper, flags, and environment setup to be silently ignored.

Knowledge Base Used: infisical run Secret Injection Flow

break
fi
done

zle .accept-line
}

zle -N accept-line _infisical_auto_run_accept_line

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.

P1 Existing accept-line widget is discarded

When a user already has a custom or plugin-provided accept-line widget, this registration replaces it and the wrapper delegates directly to the built-in .accept-line, causing the existing Enter-key behavior to stop running.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

fi
`

var shellInitCmd = &cobra.Command{
Use: "shell-init [zsh]",
Short: "prints shell integration for automatically injecting secrets",
Args: cobra.ExactArgs(1),
DisableFlagsInUseLine: true,
RunE: func(cmd *cobra.Command, args []string) error {
if args[0] != "zsh" {
return fmt.Errorf("unsupported shell %q, supported shells: zsh", args[0])
}

_, err := fmt.Fprint(cmd.OutOrStdout(), zshShellInit)
return err
},
}

func init() {
RootCmd.AddCommand(shellInitCmd)
}
19 changes: 19 additions & 0 deletions packages/cmd/shell_init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmd

import (
"strings"
"testing"
)

func TestZshShellInit(t *testing.T) {
for _, expected := range []string{
"if [[ -o interactive ]]; then",
"_infisical_auto_run_prefixes=(npm pnpm bun node)",
"BUFFER=\"infisical run -- $BUFFER\"",
"zle .accept-line",
} {
if !strings.Contains(zshShellInit, expected) {
t.Errorf("shell initialization script does not contain %q", expected)
}
}
}