Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
12e7d4d
ux(empty,card): the two shared pieces every other phase 3 item needs
guan4tou2 Aug 21, 2026
40a4d85
ux(sidebar,status): fix the nav order, print the numbers, drop the ⏱ …
guan4tou2 Aug 21, 2026
d649b24
ux(palette): one ⌘K everywhere, ⌘F for filtering, Search page deleted
guan4tou2 Aug 21, 2026
12daf45
fix(platform): ask whether it is a Mac, not whether it is not Windows
guan4tou2 Aug 21, 2026
90e1cfb
ux(sidebar,empty): the 1c deviations, and the residue the drag remova…
guan4tou2 Aug 21, 2026
fea64d8
design(buttons): §4's four levels in one component, primaries filled …
guan4tou2 Aug 21, 2026
2d692ba
a11y(fills): dark text on every fill, because white fails on all of them
guan4tou2 Aug 21, 2026
6512c22
ux(settings): a left list of thirteen categories, and plugins flattened
guan4tou2 Aug 21, 2026
36226c5
model(capture): group sources by what they capture, drop the false se…
guan4tou2 Aug 21, 2026
43fab71
ux(timeline): three view modes replace eight side-by-side toggles
guan4tou2 Aug 21, 2026
1686850
docs: the core moves from defensibility to knowability
guan4tou2 Aug 21, 2026
3ef1e06
docs: the operator is the consumer, not the purple team
guan4tou2 Aug 21, 2026
59ff5fc
revert: the timeline view modes, and restore the Search view
guan4tou2 Aug 21, 2026
1d66add
ux(export): one control, and three settings groups that were never se…
guan4tou2 Aug 22, 2026
5603ae9
feat(plugins)!: remove the marketplace, keep what is installed
guan4tou2 Aug 22, 2026
05b4b0f
feat(search): full-text search inside terminal recordings
guan4tou2 Aug 22, 2026
29d356c
test(e2e): pin the chrome/content selection boundary in a running app
guan4tou2 Aug 22, 2026
aba872e
ux(settings): 30 groups to 27, and two names that were hiding their c…
guan4tou2 Aug 22, 2026
2e64fc9
merge: main's scanner work, and the four things it broke
guan4tou2 Aug 22, 2026
1a77090
feat(share)!: remove cloud share, keep the bundle
guan4tou2 Aug 22, 2026
c134630
ux(http): activities, not connections — §3 applied to the HTTP panel
guan4tou2 Aug 22, 2026
a507cf9
docs: salvage the decomposition suite from PR #8
guan4tou2 Aug 22, 2026
56073ea
feat(plugins): salvage the c2-tailers pack from PR #8
guan4tou2 Aug 22, 2026
1d5976c
test: two Windows-only failures, both mine, both line-ending/exec-bit…
guan4tou2 Aug 22, 2026
66a6f38
feat(capture): connection-level network capture
guan4tou2 Aug 22, 2026
6a82f77
feat(retention): size-pressure eviction for the body store
guan4tou2 Aug 23, 2026
47cc2ef
feat(timeline): target focus, and the TargetView crash it uncovered
guan4tou2 Aug 23, 2026
98a7bba
feat(deconfliction)!: remove the blue-team webhook
guan4tou2 Aug 23, 2026
ddc2606
feat(mcp)!: remove the app-hosted MCP server
guan4tou2 Aug 23, 2026
1d479fa
feat(operators)!: remove multi-operator token management, keep identity
guan4tou2 Aug 23, 2026
65170ec
feat(capture): credential_use producer for command-line secrets
guan4tou2 Aug 23, 2026
cfe990a
feat(capture): PowerShell Start-Transcript follower for Windows output
guan4tou2 Aug 23, 2026
8b2429e
chore(ci): tell GitGuardian the test fixtures are fixtures
guan4tou2 Aug 23, 2026
7a6e7cc
test(credential): neutralize fixtures so the secret scanner stops fla…
guan4tou2 Aug 23, 2026
f01e71d
test(credential): re-add the detector suite with no literal credentia…
guan4tou2 Aug 23, 2026
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
66 changes: 3 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ notice and choose **Open Anyway**.
<td width="50%"><a href="docs/screenshots/dashboard.jpg"><img src="docs/screenshots/dashboard.jpg" alt="Dashboard" /></a><br/><b>Dashboard</b> — capture health, safe-IP status, session counters, engagement metadata, keyboard shortcuts</td>
<td width="50%"><a href="docs/screenshots/timeline.jpg"><img src="docs/screenshots/timeline.jpg" alt="Timeline" /></a><br/><b>Attack Timeline</b> — swim-lane view across Shell / Agent / HTTP / DNS / Pivot / Screenshots / Loot / Marks / System with cluster popups, per-command replay, and full-session `.cast` replay</td>
</tr>
<tr>
<td width="50%"><a href="docs/screenshots/marketplace.jpg"><img src="docs/screenshots/marketplace.jpg" alt="Marketplace" /></a><br/><b>Plugin Marketplace</b> — fetch a signed registry, install with sha256 + Ed25519 verification, one-click trust publishers advertised in the index</td>
<td width="50%"><a href="docs/screenshots/cloud-share.jpg"><img src="docs/screenshots/cloud-share.jpg" alt="Cloud share" /></a><br/><b>Cloud share bundle</b> — preview review (events / sanitize / screenshots / casts, raw + zipped estimate), hard review-gate checkbox, expiry picker, stub / HTTPS backend switch</td>
</tr>
</table>

## Why RedLog
Expand All @@ -57,17 +53,15 @@ Penetration testers need a complete, tamper-evident record of every action taken
**Key differentiators:**

- **Zero-friction capture** — installs, starts recording, stays out of your way
- **AI agent native** — MCP server + shell hooks let Claude Code, Codex, and GPT log directly into your timeline
- **AI agent native** — shell hooks let Claude Code, Codex, and GPT log directly into your timeline
- **Scope-aware** — root-domain matching alerts you when tools touch out-of-scope targets without false positives on unrelated hosts
- **Per-operator identity** — every event carries an operator id resolved from an API token; teammates and agents get their own tokens ([details](docs/operators.md))
- **Operator identity** — every event carries an operator id resolved from the API token
- **Evidence chain + OpenTimestamps** — append-only SHA-256 chain, hourly anchored to public OpenTimestamps calendars, one-command `.ots` bundle export for third-party `ots verify` ([details](docs/audit-trail.md))
- **Ghostwriter-compatible event schema** — first-class `dns`, `credential_use`, `c2_checkin`, `file_transfer` types plus standard `dest_ip / dest_host / mitre_ttp / description` keys ([details](docs/event-schema.md))
- **Signed evidence bundle** — `redlog-cli export bundle` produces a self-contained directory with SHA-256 manifest ready for delivery
- **Entropy-based redaction** — high-entropy tokens and per-project allow/denylist patterns are auto-redacted from captured output
- **Clock hardening** — every event carries wall-clock, monotonic, and NTP offset
- **Deconfliction webhook** — optional signed feed to the blue team's SOC on marker / scope-violation / cred-use events ([details](docs/deconfliction.md))
- **asciinema terminal recording** — every RedLog terminal pane produces a `.cast` file with SHA-256 stored on session end; the timeline exposes both **per-command replay** (▶ Replay stdout) and **full-session replay** (▶ Replay entire session) — critical when the operator ssh'd into a remote host and the local `ssh` command_end is the only chain entry from that stretch
- **Built-in MCP server (HTTP)** — the app hosts its own MCP endpoint, live the moment RedLog opens; agents operate the app (markers, scope, anchoring) without spawning a subprocess ([details](docs/agent-integration.md#2-mcp-server-operate-the-app))
- **One-click proxied browser** — launches Chromium through your mitmproxy with CDP enabled and a project-local profile, so captured traffic and QuickMarks work without touching your daily browser ([details](docs/agent-integration.md#proxied-browser))
- **Internal-pivot awareness** — auto-detects ligolo-ng / chisel / `ssh -D/-L/-R` / sshuttle / proxychains from shell commands and records a first-class `pivot` event (intermediate node, route, SOCKS port, MITRE T1090/T1572) so the timeline shows the lateral-movement topology; plain `ssh user@host` also fires a pivot so the timeline reflects "attention moved to a remote host" ([details](docs/event-schema.md#pivot-events))
- **VPS deployment** — `hooks/vps-deploy.sh install user@vps && hooks/vps-deploy.sh tunnel user@vps` copies the shell hook to a remote box and opens a reverse-tunnel session, so every command run on the VPS lands in the local chain in real time
Expand Down Expand Up @@ -221,56 +215,6 @@ SHELL=/path/to/redlog/hooks/codex-wrapper.sh codex run "scan the target"
./hooks/codex-wrapper.sh nmap -sV target.com
```

### Layer 2: MCP Server (operate the app) — control plane, not logging

RedLog hosts its own MCP server **over HTTP**, so it's live whenever the app is open — no subprocess to spawn. Use it to *operate* RedLog: create markers, check scope, anchor the chain, read history. Hooks do the logging; MCP does not duplicate it.

Set up in **Settings ▸ Team & Integrations ▸ MCP Server**, then:

```bash
claude mcp add --transport http redlog http://127.0.0.1:6660/mcp \
--header "Authorization: Bearer <mcp-token>"
```

(A stdio bridge is available as a fallback — see [docs](docs/agent-integration.md#2-mcp-server-operate-the-app).)

```bash
claude mcp add redlog -- node /path/to/redlog/mcp/redlog-mcp-server.js
```

**18 available tools (HTTP or stdio):**

| Tool | Description |
|------|-------------|
| `redlog_status` | IP state, event count, scope violations |
| `redlog_whoami` | Confirm which operator token is loaded |
| `redlog_operators_list` | List every registered operator |
| `redlog_mark` | Create a timestamped marker (finding, phase change, note) |
| `redlog_log_event` | Log a raw event with custom type and data |
| `redlog_search` | Full-text search across all events |
| `redlog_events` | Query recent events by type/target |
| `redlog_scope` | Get scope config and violations |
| `redlog_config` | Get project configuration |
| `redlog_quickmark` | Bookmark a URL/finding |
| `redlog_quickmarks_list` | List all bookmarks |
| `redlog_loot_scan` | Scan text for credentials/secrets |
| `redlog_screenshot` | Capture desktop screenshot |
| `redlog_recording` | Pause/resume/toggle recording |
| `redlog_chain_status` | Chain length + latest OTS anchor |
| `redlog_chain_anchor_now` | Anchor current chain head to OpenTimestamps |
| `redlog_chain_verify` | Fast prefix check on latest anchor |
| `redlog_chain_upgrade` | Fetch upgraded OTS proofs for pending anchors |

Ship-ready skill file at [`docs/skills/redlog-pentest.md`](docs/skills/redlog-pentest.md) — copy to `~/.claude/skills/` to opt an agent into the full flow.

**Example agent interaction:**

```
User: "Check if this target is in scope, then run a port scan and log the results"

Agent calls: redlog_scope → confirms target → runs nmap → redlog_mark with findings
```

### Layer 3: HTTP API (Universal)

Direct REST API for scripts, custom agents, and non-MCP tools.
Expand Down Expand Up @@ -299,7 +243,7 @@ curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:$PORT/api/status
| POST | `/api/loot/scan` | Scan text for secrets |
| POST | `/api/screenshot` | Trigger manual capture |
| GET | `/api/whoami` | Operator identity for this token |
| GET/POST/PATCH/DELETE | `/api/operators[/…]` | Operator token management |
| GET | `/api/operators` | List operators (attribution) |
| GET | `/api/chain` | Chain length + last anchor |
| GET/POST | `/api/anchors` | List / trigger OpenTimestamps anchoring |
| GET | `/api/anchors/verify` | Fast integrity check |
Expand All @@ -326,10 +270,8 @@ See [`docs/codex-tools.json`](docs/codex-tools.json) for OpenAI-compatible funct
### More reading

- [Agent integration](docs/agent-integration.md) — full REST + MCP + hook reference
- [Operators & tokens](docs/operators.md) — multi-operator identity, token lifecycle
- [Audit trail](docs/audit-trail.md) — hash chain + OpenTimestamps + full re-walk + bundle export
- [Event schema](docs/event-schema.md) — standard agent_type + data keys (Ghostwriter-compatible)
- [Deconfliction webhook](docs/deconfliction.md) — when/how to feed the blue team
- [Plugin development](docs/plugin-development.md) — extend RedLog: 🟢 declarative packs + 🔴 trust-gated MCP tools
- [Skill: redlog-pentest](docs/skills/redlog-pentest.md) — ready-to-copy Claude Code skill

Expand Down Expand Up @@ -377,7 +319,6 @@ Hooks
└── codex-wrapper.sh Shell wrapper for Codex/GPT

MCP Server
└── redlog-mcp-server.js 18-tool MCP server (stdio transport)
```

## Project Structure
Expand Down Expand Up @@ -421,7 +362,6 @@ hooks/
shell-preexec-hook.sh zsh/bash preexec → RedLog
codex-wrapper.sh shell wrapper for any agent
mcp/
redlog-mcp-server.js MCP server (18 tools, stdio transport)
cli/
redlog-cli.js CLI tool for external integration
shell/
Expand Down
51 changes: 10 additions & 41 deletions cli/redlog-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Usage:
redlog-cli health
redlog-cli token
redlog-cli whoami
redlog-cli operators [list|add <name>|rotate <id>|revoke <id>|delete <id>]
redlog-cli operators [list]
redlog-cli chain [status|anchor|verify [--full]|anchors|export-ots <id> [--out <file>]|upgrade [<id>|--all]]
redlog-cli export bundle

Expand All @@ -132,7 +132,6 @@ Examples:
redlog-cli search "password"
redlog-cli loot "root:x:0:0:root:/root:/bin/bash"
redlog-cli whoami
redlog-cli operators add "Codex agent"
redlog-cli chain anchor
curl -s -H "Authorization: Bearer $(redlog-cli token)" http://127.0.0.1:6660/api/events
`)
Expand Down Expand Up @@ -368,47 +367,17 @@ Examples:

case 'operators': {
const sub = positional[0] || 'list'
if (sub === 'list') {
const res = await request('GET', '/api/operators')
if (res.status === 200) {
for (const op of res.data.operators) {
const tag = op.isPrimary ? '[PRIMARY]' : op.revokedAt ? '[REVOKED]' : ' '
console.log(` ${tag} ${op.id.padEnd(28)} ${op.name}`)
}
} else { console.error(`Error ${res.status}:`, res.data); process.exit(1) }
} else if (sub === 'add') {
const name = positional.slice(1).join(' ')
if (!name) { console.error('Usage: redlog-cli operators add <name>'); process.exit(1) }
const res = await request('POST', '/api/operators', { name })
if (res.status === 201) {
console.log(`Created: ${res.data.operator.id}`)
console.log(`Token (save now — not shown again):`)
console.log(` ${res.data.token}`)
} else { console.error(`Error ${res.status}:`, res.data); process.exit(1) }
} else if (sub === 'rotate') {
const id = positional[1]
if (!id) { console.error('Usage: redlog-cli operators rotate <id>'); process.exit(1) }
const res = await request('POST', `/api/operators/${encodeURIComponent(id)}/rotate`)
if (res.status === 200) {
console.log(`New token for ${id}:`)
console.log(` ${res.data.token}`)
} else { console.error(`Error ${res.status}:`, res.data); process.exit(1) }
} else if (sub === 'revoke') {
const id = positional[1]
if (!id) { console.error('Usage: redlog-cli operators revoke <id>'); process.exit(1) }
const res = await request('POST', `/api/operators/${encodeURIComponent(id)}/revoke`)
console.log(res.status === 200 ? `Revoked ${id}` : `Error ${res.status}: ${JSON.stringify(res.data)}`)
if (res.status !== 200) process.exit(1)
} else if (sub === 'delete') {
const id = positional[1]
if (!id) { console.error('Usage: redlog-cli operators delete <id>'); process.exit(1) }
const res = await request('DELETE', `/api/operators/${encodeURIComponent(id)}`)
console.log(res.status === 200 ? `Deleted ${id}` : `Error ${res.status}: ${JSON.stringify(res.data)}`)
if (res.status !== 200) process.exit(1)
} else {
console.error(`Unknown operators subcommand: ${sub}. Use list|add|rotate|revoke|delete`)
if (sub !== 'list') {
console.error(`Unknown operators subcommand: ${sub}. Only 'list' remains.`)
process.exit(1)
}
const res = await request('GET', '/api/operators')
if (res.status === 200) {
for (const op of res.data.operators) {
const tag = op.isPrimary ? '[PRIMARY]' : op.revokedAt ? '[REVOKED]' : ' '
console.log(` ${tag} ${op.id.padEnd(28)} ${op.name}`)
}
} else { console.error(`Error ${res.status}:`, res.data); process.exit(1) }
break
}

Expand Down
179 changes: 0 additions & 179 deletions cli/redlog-sign.js

This file was deleted.

Loading