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
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,25 @@ Open `http://localhost:3000`, register, and start a session.
./run.sh help # Full help
```

```powershell
git clone https://github.com/bugbasesecurity/pentest-copilot.git
cd pentest-copilot
.\run.ps1 start
```

Open `http://localhost:3000`, register, and start a session.

`run.sh` handles config file generation, Docker builds, and container orchestration. On first run it prompts for your model provider and API key. Use `.\run.ps1 start -q` to skip prompts on subsequent runs.

```powershell
.\run.ps1 stop # Stop all containers
.\run.ps1 logs # Tail logs
.\run.ps1 status # Container status
.\run.ps1 config # Update configuration
.\run.ps1 dev # Developer mode (infra only, run frontend/backend locally)
.\run.ps1 help # Full help
```

### System Requirements

| | Minimum |
Expand Down Expand Up @@ -95,6 +114,10 @@ Full documentation lives in the **[Wiki](https://github.com/bugbasesecurity/pent
./run.sh dev # Starts MongoDB + Redis in Docker
```

```powershell
.\run.ps1 dev # Starts MongoDB + Redis in Docker
```

Then in separate terminals:

```bash
Expand All @@ -103,6 +126,12 @@ cd backend && pnpm run dev # Backend server (port 8080)
cd frontend && pnpm install && pnpm run dev # Frontend (port 3000)
```

```powershell
cd backend; pnpm install; pnpm run watch # TypeScript compiler
cd backend; pnpm run dev # Backend server (port 8080)
cd frontend; pnpm install; pnpm run dev # Frontend (port 3000)
```

See the [Wiki](https://github.com/bugbasesecurity/pentest-copilot/wiki/Home) for detailed setup instructions.

## Authors
Expand Down
2 changes: 1 addition & 1 deletion backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ ENV DISPLAY=:99
RUN pnpm run build

COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh && sed -i 's/\r$//' /usr/local/bin/entrypoint.sh

EXPOSE 8080 6080

Expand Down
18 changes: 9 additions & 9 deletions backend/src/controllers/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ export const autoSetupVNC = async (_req: Request, res: Response) => {
const randomPassword = generateRandomPassword();
await execCmd(
`mkdir -p ~/.vnc && ` +
`echo '#!/bin/bash\\nexport DISPLAY=${VNC_DISPLAY}\\n[ -f $$HOME/.Xresources ] && xrdb $$HOME/.Xresources\\nif command -v startxfce4 >/dev/null 2>&1; then\\n startxfce4 &\\nelif command -v openbox-session >/dev/null 2>&1; then\\n openbox-session &\\nelse\\n xterm &\\nfi' > ~/.vnc/xstartup && ` +
`echo -e '#!/bin/bash\nexport DISPLAY=${VNC_DISPLAY}\nunset SESSION_MANAGER\n[ -f $$HOME/.Xresources ] && xrdb $$HOME/.Xresources\nif command -v xfce4-session >/dev/null 2>&1; then\n xfce4-session &\nelif command -v openbox-session >/dev/null 2>&1; then\n openbox-session &\nelse\n xterm &\nfi' > ~/.vnc/xstartup && ` +
`chmod +x ~/.vnc/xstartup`
);
// Kill all existing VNC/Xvfb processes for a clean start
Expand All @@ -694,19 +694,19 @@ export const autoSetupVNC = async (_req: Request, res: Response) => {
if (isXvncDirect) {
await execCmd(
`${vncBin} ${VNC_DISPLAY} -geometry 1280x800 -depth 24 -rfbport ${VNC_RFBPORT} ` +
`-SecurityTypes VncAuth -PasswordFile ~/.vnc/passwd ` +
`-rfbauth ~/.vnc/passwd ` +
`-pn > /dev/null 2>&1 &`
);
await new Promise((resolve) => setTimeout(resolve, 1500));
await execCmd(`export DISPLAY=${VNC_DISPLAY} && ~/.vnc/xstartup &`);
await execCmd(`export DISPLAY=${VNC_DISPLAY} && nohup ~/.vnc/xstartup > /dev/null 2>&1 &`);
} else if (isX11vnc) {
await execCmd(
"command -v Xvfb >/dev/null 2>&1 || " +
"(export DEBIAN_FRONTEND=noninteractive && sudo apt-get install -y -qq xvfb 2>&1 || true)"
);
await execCmd(`Xvfb ${VNC_DISPLAY} -screen 0 1280x800x24 > /dev/null 2>&1 &`);
await new Promise((resolve) => setTimeout(resolve, 2000));
await execCmd(`export DISPLAY=${VNC_DISPLAY} && ~/.vnc/xstartup &`);
await execCmd(`export DISPLAY=${VNC_DISPLAY} && nohup ~/.vnc/xstartup > /dev/null 2>&1 &`);
await execCmd(
`x11vnc -display ${VNC_DISPLAY} -rfbport ${VNC_RFBPORT} -passwd '${escapedPw}' ` +
`-forever -shared -noxdamage > /dev/null 2>&1 &`
Expand Down Expand Up @@ -1102,7 +1102,7 @@ export const repairVNC = async (req: Request, res: Response) => {
try {
await execSSHCommand(
`mkdir -p ~/.vnc && ` +
`echo '#!/bin/bash\\nexport DISPLAY=${VNC_DISPLAY}\\n[ -f $$HOME/.Xresources ] && xrdb $$HOME/.Xresources\\nif command -v startxfce4 >/dev/null 2>&1; then\\n startxfce4 &\\nelif command -v openbox-session >/dev/null 2>&1; then\\n openbox-session &\\nelse\\n xterm &\\nfi' > ~/.vnc/xstartup && ` +
`echo -e '#!/bin/bash\nexport DISPLAY=${VNC_DISPLAY}\nunset SESSION_MANAGER\n[ -f $$HOME/.Xresources ] && xrdb $$HOME/.Xresources\nif command -v xfce4-session >/dev/null 2>&1; then\n xfce4-session &\nelif command -v openbox-session >/dev/null 2>&1; then\n openbox-session &\nelse\n xterm &\nfi' > ~/.vnc/xstartup && ` +
`chmod +x ~/.vnc/xstartup`
);
log.push(`Configured xstartup with DISPLAY=${VNC_DISPLAY}`);
Expand Down Expand Up @@ -1145,11 +1145,11 @@ export const repairVNC = async (req: Request, res: Response) => {
console.log(`[VNC Repair] Starting Xvnc directly: ${vncBin} ${VNC_DISPLAY} rfbport=${VNC_RFBPORT}`);
await execSSHCommand(
`${vncBin} ${VNC_DISPLAY} -geometry 1280x800 -depth 24 -rfbport ${VNC_RFBPORT} ` +
`-SecurityTypes VncAuth -PasswordFile ~/.vnc/passwd ` +
`-rfbauth ~/.vnc/passwd ` +
`-pn > /dev/null 2>&1 &`
);
await new Promise((r) => setTimeout(r, 1500));
await execSSHCommand(`export DISPLAY=${VNC_DISPLAY} && ~/.vnc/xstartup &`);
await execSSHCommand(`export DISPLAY=${VNC_DISPLAY} && nohup ~/.vnc/xstartup > /dev/null 2>&1 &`);
log.push(`Started Xvnc directly on ${VNC_DISPLAY}`);
console.log(`[VNC Repair] Started Xvnc directly on ${VNC_DISPLAY}`);
} else if (isX11vnc) {
Expand All @@ -1167,7 +1167,7 @@ export const repairVNC = async (req: Request, res: Response) => {
);
console.log("[VNC Repair] Xvfb process check:", xvfbCheck.trim() || "(not found)");

await execSSHCommand(`export DISPLAY=${VNC_DISPLAY} && ~/.vnc/xstartup &`);
await execSSHCommand(`export DISPLAY=${VNC_DISPLAY} && nohup ~/.vnc/xstartup > /dev/null 2>&1 &`);
const escaped = (savedPassword || "").replace(/'/g, "'\\''");
await execSSHCommand(
`x11vnc -display ${VNC_DISPLAY} -rfbport ${VNC_RFBPORT} -passwd '${escaped}' -forever -shared -noxdamage > /dev/null 2>&1 &`
Expand Down Expand Up @@ -1546,7 +1546,7 @@ export const startMagnitudeAgent = async (req: Request, res: Response) => {
targetUrl,
});
} catch (agentError: any) {
try { await agent.stop(); } catch {}
try { await agent.stop(); } catch { }
return res.status(500).json({
message: `Browser agent failed: ${formatMagnitudeError(agentError)}`,
goal,
Expand Down
8 changes: 4 additions & 4 deletions backend/src/controllers/vnc.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const getVNCCredentials = async (req: Request, res: Response) => {

// Ensure xstartup exists with DISPLAY export
await exec(
`mkdir -p ~/.vnc && echo '#!/bin/bash\\nexport DISPLAY=${VNC_DISPLAY}\\n[ -f $$HOME/.Xresources ] && xrdb $$HOME/.Xresources\\nif command -v startxfce4 >/dev/null 2>&1; then\\n startxfce4 &\\nelif command -v openbox-session >/dev/null 2>&1; then\\n openbox-session &\\nelse\\n xterm &\\nfi' > ~/.vnc/xstartup && chmod +x ~/.vnc/xstartup`
`mkdir -p ~/.vnc && echo -e '#!/bin/bash\\nexport DISPLAY=${VNC_DISPLAY}\\nunset SESSION_MANAGER\\n[ -f $$HOME/.Xresources ] && xrdb $$HOME/.Xresources\\nif command -v xfce4-session >/dev/null 2>&1; then\\n xfce4-session &\\nelif command -v openbox-session >/dev/null 2>&1; then\\n openbox-session &\\nelse\\n xterm &\\nfi' > ~/.vnc/xstartup && chmod +x ~/.vnc/xstartup`
);

// Kill all existing VNC/Xvfb for a clean start
Expand Down Expand Up @@ -103,18 +103,18 @@ export const getVNCCredentials = async (req: Request, res: Response) => {
if (isXvncDirect) {
await exec(
`${vncBin} ${VNC_DISPLAY} -geometry 1280x800 -depth 24 -rfbport ${VNC_RFBPORT} ` +
`-SecurityTypes VncAuth -PasswordFile ~/.vnc/passwd ` +
`-rfbauth ~/.vnc/passwd ` +
`-pn > /dev/null 2>&1 &`
);
await new Promise((r) => setTimeout(r, 1500));
await exec(`export DISPLAY=${VNC_DISPLAY} && ~/.vnc/xstartup &`);
await exec(`export DISPLAY=${VNC_DISPLAY} && nohup ~/.vnc/xstartup > /dev/null 2>&1 &`);
} else if (isX11vnc) {
await exec(
"command -v Xvfb >/dev/null 2>&1 || (export DEBIAN_FRONTEND=noninteractive && sudo apt-get install -y -qq xvfb 2>&1 || true)"
);
await exec(`Xvfb ${VNC_DISPLAY} -screen 0 1280x800x24 > /dev/null 2>&1 &`);
await new Promise((r) => setTimeout(r, 2000));
await exec(`export DISPLAY=${VNC_DISPLAY} && ~/.vnc/xstartup &`);
await exec(`export DISPLAY=${VNC_DISPLAY} && nohup ~/.vnc/xstartup > /dev/null 2>&1 &`);
await exec(
`x11vnc -display ${VNC_DISPLAY} -rfbport ${VNC_RFBPORT} -passwd '${escapedPassword}' -forever -shared -noxdamage > /dev/null 2>&1 &`
);
Expand Down
4 changes: 2 additions & 2 deletions kali/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ RUN mkdir -p /var/run/sshd && \
EXPOSE 22 4200 1194/udp 9020

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
RUN chmod +x /entrypoint.sh && sed -i 's/\r$//' /entrypoint.sh

# ── Layer 2: Base utilities + build deps (needed for runtime tool installs) ──
RUN apt-get update && \
Expand Down Expand Up @@ -70,7 +70,7 @@ RUN apt-get update && \

# Additional security tools (Go-based & Python-based — uncomment to pre-install)
COPY tools.sh /tools.sh
RUN chmod +x /tools.sh
RUN chmod +x /tools.sh && sed -i 's/\r$//' /tools.sh
# RUN /tools.sh

ENTRYPOINT ["/entrypoint.sh"]
Loading