Skip to content
Merged
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
36 changes: 10 additions & 26 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -177,30 +177,13 @@ RUN pip3 install --break-system-packages \
# Additional security-focused Python packages
RUN pip3 install --break-system-packages requests aiohttp jinja2 'httpx[cli]' ratelimit pycryptodomex

# Ruby forensics tool
RUN gem install zsteg

# ============================================================================
# Git-based Security Tools
# ============================================================================
RUN set -eux; \
# GraphQL schema inference
git clone https://github.com/nikitastupin/clairvoyance.git /opt/clairvoyance || true && \
if [ -d /opt/clairvoyance ]; then \
cd /opt/clairvoyance && \
python3 -m venv venv && \
. venv/bin/activate && \
pip install . || true; \
fi && \
# JWT analysis tool
git clone https://github.com/ticarpi/jwt_tool.git /opt/jwt_tool || true && \
if [ -f /opt/jwt_tool/jwt_tool.py ]; then chmod +x /opt/jwt_tool/jwt_tool.py; fi && \
# Template injection testing
git clone https://github.com/epinna/tplmap.git /opt/tplmap || true && \
if [ -f /opt/tplmap/tplmap.py ]; then chmod +x /opt/tplmap/tplmap.py; fi && \
# PHP object injection
git clone https://github.com/ambionics/phpggc.git /opt/phpggc || true && \
if [ -f /opt/phpggc/phpggc ]; then chmod +x /opt/phpggc/phpggc; fi && \
# Git repository dumper
git clone https://github.com/internetwache/GitTools.git /opt/gittools && \
chmod +x /opt/gittools/Dumper/gitdumper.sh /opt/gittools/Extractor/extractor.sh && \
Expand Down Expand Up @@ -245,14 +228,8 @@ RUN set -eux; \
# Create Wrapper Scripts for Python Tools
# ============================================================================
RUN set -eux; \
# Clairvoyance wrapper
([ -d /opt/clairvoyance ] && echo '#!/bin/bash\ncd /opt/clairvoyance && source venv/bin/activate && python -m clairvoyance "$@"' > /usr/local/bin/clairvoyance && chmod +x /usr/local/bin/clairvoyance) || true && \
# JWT Tool wrapper
([ -f /opt/jwt_tool/jwt_tool.py ] && echo '#!/bin/bash\npython3 /opt/jwt_tool/jwt_tool.py "$@"' > /usr/local/bin/jwt-tool && chmod +x /usr/local/bin/jwt-tool) || true && \
# Tplmap wrapper
([ -f /opt/tplmap/tplmap.py ] && echo '#!/bin/bash\npython3 /opt/tplmap/tplmap.py "$@"' > /usr/local/bin/tplmap && chmod +x /usr/local/bin/tplmap) || true && \
# PHPGGC symlink
([ -f /opt/phpggc/phpggc ] && ln -sf /opt/phpggc/phpggc /usr/local/bin/phpggc) || true
([ -f /opt/jwt_tool/jwt_tool.py ] && echo '#!/bin/bash\npython3 /opt/jwt_tool/jwt_tool.py "$@"' > /usr/local/bin/jwt-tool && chmod +x /usr/local/bin/jwt-tool) || true

# ============================================================================
# Go-based Security Tools
Expand All @@ -262,6 +239,14 @@ RUN set -eux; \
go install github.com/hahwul/dalfox/v2@latest && \
go install github.com/jpillora/chisel@latest

# ============================================================================
# TestSSL Symlink - Allow access via both 'testssl' and 'testssl.sh'
# ============================================================================
RUN set -eux; \
if command -v testssl >/dev/null 2>&1; then \
ln -sf $(which testssl) /usr/local/bin/testssl.sh; \
fi

# ============================================================================
# Tool Validation
# ============================================================================
Expand All @@ -287,6 +272,7 @@ RUN set -eux; \
which gobuster && echo "✓ gobuster" && \
which dirsearch && echo "✓ dirsearch" && \
which testssl && echo "✓ testssl" && \
which testssl.sh && echo "✓ testssl.sh" && \
which nuclei && echo "✓ nuclei" && \
which hydra && echo "✓ hydra" && \
which smbclient && echo "✓ smbclient" && \
Expand All @@ -299,8 +285,6 @@ RUN set -eux; \
which chisel && echo "✓ chisel" && \
which interactsh-client && echo "✓ interactsh-client" && \
which jwt-tool && echo "✓ jwt_tool" && \
which tplmap && echo "✓ tplmap" && \
which phpggc && echo "✓ phpggc" && \
which gitdumper && echo "✓ gitdumper" && \
which linpeas && echo "✓ linpeas" && \
which trufflehog && echo "✓ trufflehog" && \
Expand Down
20 changes: 14 additions & 6 deletions lib/ai/tools/run-terminal-cmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ export const createRunTerminalCmd = (context: ToolContext) => {
context;

// Wait instructions for E2B sandbox (local sandbox uses different commands)
const waitForProcessInstruction = `To wait for a background process to complete, use \`tail --pid=<pid> -f /dev/null\`. This will block until the process exits. Example workflow: Start scan with is_background=true (returns PID 12345) → Wait with \`tail --pid=12345 -f /dev/null\``;
// Note: Code also handles 'while ps -p' loops for robustness, but we only document tail --pid
const waitForProcessInstruction = `To wait for a background process to complete, use \`tail --pid=<pid> -f /dev/null\`. This blocks until the process exits and gets extended timeout (up to ${Math.floor(MAX_COMMAND_EXECUTION_TIME / 1000 / 60)} minutes). Example workflow: Start scan with is_background=true (returns PID 12345) → Wait with \`tail --pid=12345 -f /dev/null\``;

const timeoutWaitInstruction = `If a foreground command times out after 60 seconds but is still running and producing results (you'll see the timeout message), the process continues in the background. To wait for it: 1) Note the PID from the error/timeout message or use \`ps aux | grep <command_name>\` to find it, 2) Use \`tail --pid=<pid> -f /dev/null\` to wait for completion. This is common for long scans like comprehensive nmap, sqlmap, or nuclei scans.`;
const timeoutWaitInstruction = `If a foreground command times out after ${STREAM_TIMEOUT_SECONDS} seconds but is still running and producing results (you'll see the timeout message), the process continues in the background. To wait for it: 1) Note the PID from the error/timeout message or use \`ps aux | grep <command_name>\` to find it, 2) Use \`tail --pid=<pid> -f /dev/null\` to wait for completion. This is common for long scans like comprehensive nmap, sqlmap, or nuclei scans.`;

return tool({
description: `Execute a command on behalf of the user.
Expand Down Expand Up @@ -215,17 +216,24 @@ If you are generating files:
});
}

// For tail --pid commands (used to wait for processes), use MAX_COMMAND_EXECUTION_TIME
// For wait commands (tail --pid or while ps -p loops), use MAX_COMMAND_EXECUTION_TIME
// instead of STREAM_TIMEOUT_SECONDS since they're designed to wait for long-running processes
const isWaitCommand = command.trim().startsWith("tail --pid");
const isTailWait = command.trim().startsWith("tail --pid");
const isWhilePsWait = /while\s+ps\s+-p\s+\d+/.test(command);
const isWaitCommand = isTailWait || isWhilePsWait;
const streamTimeout = isWaitCommand
? Math.floor(MAX_COMMAND_EXECUTION_TIME / 1000)
: STREAM_TIMEOUT_SECONDS;

// Extract PID from tail --pid command for user-friendly messages
// Extract PID from wait command for user-friendly messages
let waitingForPid: number | null = null;
if (isWaitCommand) {
const pidMatch = command.match(/tail\s+--pid[=\s]+(\d+)/);
// Try tail --pid pattern first
let pidMatch = command.match(/tail\s+--pid[=\s]+(\d+)/);
// If not found, try while ps -p pattern
if (!pidMatch) {
pidMatch = command.match(/while\s+ps\s+-p\s+(\d+)/);
}
if (pidMatch) {
waitingForPid = parseInt(pidMatch[1], 10);
createTerminalWriter(
Expand Down