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
2 changes: 1 addition & 1 deletion .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy experimental docs to GitHub Pages
name: Deploy docs to GitHub Pages

on:
push:
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</p>

<p align="center">
A GitHub-native, encrypted control plane for authorized systems research.
GitHub-native command-and-control for authorized security research, with encrypted multi-channel transport and resilient failover.
</p>

> [!IMPORTANT]
Expand All @@ -21,15 +21,25 @@ OctoC2 combines a TypeScript beacon, durable controller, local operator
dashboard, and CLI. GitHub-backed and direct transports share one signed task
protocol, one identity model, and the same result-ownership rules.

**Documentation:** [Browse the complete manual](docs/README.md) or open the
[documentation site](https://dstours.github.io/OctoC2/).

## Start here

| I want to… | Read or run |
|---|---|
| Browse all documentation | [Documentation index](docs/README.md) |
| Understand the system | [Architecture](#architecture) |
| Set up a local environment | [Local evaluation quickstart](docs/QUICKSTART.md) |
| Understand the system | [Architecture guide](docs/ARCHITECTURE.md) |
| Install the toolchain and binaries | [Installation](docs/INSTALLATION.md) |
| Configure the GitHub App, repos, and PATs | [GitHub setup](docs/GITHUB_SETUP.md) |
| Complete a first local run | [Quickstart](docs/QUICKSTART.md) |
| Configure every channel | [Channel guide](docs/CHANNELS.md) |
| Use operator commands | [CLI reference](docs/CLI.md) |
| Look up an environment variable | [Configuration reference](docs/CONFIGURATION.md) |
| Configure listeners and certificates | [Operations and assurance](docs/PRODUCTION.md) |
| Configure GitHub App recovery | [Recovery guide](docs/RECOVERY.md) |
| Diagnose a failure | [Troubleshooting](docs/TROUBLESHOOTING.md) |
| Contribute a change | [Development guide](docs/DEVELOPMENT.md) |
| Review implementation and live evidence | [Verification traceability](docs/REMEDIATION_TRACEABILITY.md) |
| Use the dashboard | [Dashboard guide](dashboard/README.md) |

Expand Down
2 changes: 1 addition & 1 deletion docs-site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="%BASE_URL%favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OctoC2 — Documentation</title>
<meta name="description" content="Architecture, setup, transport, security, and verification documentation for OctoC2. Authorized use only." />
<meta name="description" content="Complete installation, setup, channel, operations, recovery, troubleshooting, and development documentation for OctoC2. Authorized use only." />
</head>
<body>
<div id="root"></div>
Expand Down
72 changes: 62 additions & 10 deletions docs-site/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from 'react'

const owner = import.meta.env.VITE_GITHUB_OWNER || 'octoc2'
const owner = import.meta.env.VITE_GITHUB_OWNER || 'dstours'
const repo = import.meta.env.VITE_GITHUB_REPO || 'OctoC2'
const repositoryUrl = `https://github.com/${owner}/${repo}`
const docsUrl = (path: string) => `${repositoryUrl}/blob/main/${path}`
Expand Down Expand Up @@ -76,11 +76,47 @@ const transportGroups = [
]

const guides = [
{
title: 'Installation',
description: 'Install the pinned toolchain, run each component, and build platform beacon binaries.',
href: docsUrl('docs/INSTALLATION.md'),
label: 'Install',
},
{
title: 'GitHub setup',
description: 'Configure repositories, the GitHub App, least-privilege permissions, PAT roles, and rotation.',
href: docsUrl('docs/GITHUB_SETUP.md'),
label: 'Provision',
},
{
title: 'Quickstart',
description: 'Install, configure role-separated credentials, and launch the local stack.',
description: 'Build and import a pre-enrolled beacon, then verify an accepted ping result.',
href: docsUrl('docs/QUICKSTART.md'),
label: 'Start here',
label: 'First run',
},
{
title: 'Architecture',
description: 'Understand components, identity boundaries, task lifecycle, durable state, and recovery.',
href: docsUrl('docs/ARCHITECTURE.md'),
label: 'Learn',
},
{
title: 'Channel guide',
description: 'Compare every transport, permission, prerequisite, priority rule, and qualification step.',
href: docsUrl('docs/CHANNELS.md'),
label: 'Transports',
},
{
title: 'Configuration',
description: 'Look up controller, listener, beacon, OIDC, recovery, dashboard, and CLI settings.',
href: docsUrl('docs/CONFIGURATION.md'),
label: 'Reference',
},
{
title: 'CLI reference',
description: 'Use setup, enrollment, builds, inventory, tasks, results, proxy, and service commands.',
href: docsUrl('docs/CLI.md'),
label: 'Operate',
},
{
title: 'Operations & assurance',
Expand All @@ -94,6 +130,18 @@ const guides = [
href: docsUrl('docs/RECOVERY.md'),
label: 'Configure recovery',
},
{
title: 'Troubleshooting',
description: 'Diagnose GitHub errors, decrypt failures, acknowledgements, proxy, TLS, gRPC, OIDC, and state.',
href: docsUrl('docs/TROUBLESHOOTING.md'),
label: 'Diagnose',
},
{
title: 'Development',
description: 'Work with shared contracts, tests, builds, generated protocol bindings, and change checks.',
href: docsUrl('docs/DEVELOPMENT.md'),
label: 'Contribute',
},
{
title: 'Verification evidence',
description: 'Trace implementation decisions to tests, live qualifications, and cleanup records.',
Expand Down Expand Up @@ -178,6 +226,7 @@ function App() {
<a href="#quickstart">Quickstart</a>
<a href="#transports">Transports</a>
<a href="#security">Security</a>
<a href="#guides">Guides</a>
</nav>
<a className="repo-link" href={repositoryUrl}>GitHub <span aria-hidden="true">↗</span></a>
</div>
Expand All @@ -194,11 +243,12 @@ function App() {
<section className="hero">
<div className="hero-glow" aria-hidden="true" />
<div className="hero-copy">
<p className="eyebrow"><span className="pulse-dot" /> GitHub-native control plane</p>
<p className="eyebrow"><span className="pulse-dot" /> GitHub-native command and control</p>
<h1>GitHub is the transport.<br /><span>Trust is the protocol.</span></h1>
<p className="hero-lede">
OctoC2 connects a TypeScript beacon, durable controller, local dashboard,
and operator CLI through encrypted, authenticated transport paths.
OctoC2 is built for authorized security research, connecting a TypeScript
beacon, durable controller, local dashboard, and operator CLI through
encrypted multi-channel transport with resilient failover.
</p>
<div className="hero-actions">
<a className="button button-primary" href="#quickstart">Start local setup <span>→</span></a>
Expand Down Expand Up @@ -314,7 +364,7 @@ function App() {
</article>
))}
</div>
<p className="section-note">Transport selection never changes task ownership or signature requirements. Review exact permissions and prerequisites in the quickstart before enabling a channel.</p>
<p className="section-note">Transport selection never changes task ownership or signature requirements. Review exact permissions, credentials, and environment prerequisites in the channel guide before enabling a path.</p>
</section>

<section className="content-section security-section" id="security">
Expand Down Expand Up @@ -366,8 +416,8 @@ function App() {
<section className="guides-section" id="guides">
<SectionHeading
eyebrow="Guides"
title="Go deeper when you need to"
description="Focused references keep setup, operations, recovery, and evidence separate and easy to scan."
title="A complete operator and engineering manual"
description="Follow the first-run path or jump directly to setup, channels, configuration, operations, recovery, troubleshooting, and development references."
/>
<div className="guide-grid">
{guides.map((guide) => (
Expand All @@ -385,12 +435,14 @@ function App() {
<footer>
<div className="footer-brand">
<img src={logoUrl} alt="" />
<div><strong>OctoC2</strong><span>GitHub-native systems research</span></div>
<div><strong>OctoC2</strong><span>Encrypted multi-channel operations</span></div>
</div>
<div className="footer-links">
<a href={docsUrl('docs/README.md')}>Documentation index ↗</a>
<a href="#quickstart">Quickstart</a>
<a href="#security">Security</a>
<a href="#verification">Verification</a>
<a href="#guides">All guides</a>
<a href={repositoryUrl}>Repository ↗</a>
</div>
<p>Use only on systems and repositories you are explicitly authorized to test.</p>
Expand Down
137 changes: 137 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Architecture

OctoC2 is a multi-transport control plane built around one signed task
protocol. The transport may change during failover, but task identity,
encryption, ownership, replay protection, and result acceptance do not.

> [!IMPORTANT]
> **Authorized use only.** Apply these components and trust boundaries only to
> systems and repositories you own or have explicit permission to test.

## Component model

```text
Dashboard / octoctl
│ authenticated operator API or scoped GitHub API
Controller ─────────────── durable SQLite state
│ identities · tasks · delivery leases
│ signed and results · replay records · cursors
│ encrypted envelopes
GitHub APIs · HTTPS/WSS · gRPC/mTLS · signed relays
Pre-enrolled beacon ────── persistent identity and task ledger
```

| Component | Responsibility |
|---|---|
| Beacon (`implant/`) | Select transports, check in, decrypt and validate tasks, execute catalogued handlers, sign results, and recover configuration |
| Controller (`server/`) | Register identities, queue tasks, grant delivery leases, poll channels, verify results, persist state, and expose operator/direct APIs |
| Dashboard (`dashboard/`) | Present beacon health, task state, results, activity, and transport views to an authenticated operator |
| CLI (`octoctl/`) | Generate keys, provision environments, enroll/build beacons, queue tasks, inspect results, manage recovery, and configure proxies |
| Shared contracts (`shared/`) | Define canonical channel/task catalogs, signed envelopes, key IDs, validation rules, and result receipts |

## Identity and cryptography

OctoC2 deliberately separates cryptographic roles:

| Identity | Algorithm | Trust boundary |
|---|---|---|
| Operator encryption | X25519 / libsodium `crypto_box` | Tasks are sealed to a beacon; results are sealed to the operator |
| Beacon signing | Ed25519 | Check-ins and results are bound to the enrolled beacon identity |
| Recovery signing | Ed25519 | Dead-drop records and key transitions are authenticated independently of GitHub |
| TLS server identity | X.509 | HTTPS/gRPC endpoint name and CA trust |
| gRPC client identity | X.509 + SHA-256 fingerprint binding | Exact certificate-to-beacon binding |
| GitHub identity | App installation token, PAT, or OIDC claims | Authorization to the selected GitHub surface |
| Direct API identity | Operator or per-beacon bearer token | Controller route authorization |

Encryption does not replace authentication. A result is accepted only after
the signed envelope, enrolled beacon key, beacon/task ownership, task state,
replay record, and result digest all agree.

## Task lifecycle

1. An authenticated operator submits a catalogued task for a known beacon.
2. The controller validates arguments, seals the task to that beacon, signs the
envelope, and persists it as `pending`.
3. One eligible channel receives an exclusive delivery lease and publishes or
returns the task.
4. The beacon verifies and decrypts the envelope, records the task in its
durable ledger, and dispatches the matching handler once.
5. The beacon signs and encrypts the result, then returns it through the active
channel.
6. The controller verifies identity and ownership, persists the result, marks
the task complete or failed, and emits a result-acceptance receipt where the
channel supports acknowledgements.

Delivery attempts may repeat; execution may not. The durable controller state,
exclusive leases, replay store, and beacon ledger make retries safe across
process restarts.

## Transport abstraction and failover

`ConnectionFactory` builds the configured tentacles, records health, applies
the priority list, and moves to an eligible fallback after a classified
failure. A transport is eligible only when its runtime configuration and the
canonical channel prerequisites are satisfied.

GitHub transports exchange the same encrypted payload through different
artifacts. Direct transports use HTTPS or gRPC but preserve the same envelope
and ownership checks. Proxy and relay paths add signed routing; they do not
become a new source of task authority.

See [Channels](CHANNELS.md) for prerequisites and status, and [Operations and
assurance](PRODUCTION.md) for failover, listener, and acceptance policy.

## Durable state

The controller stores beacon identities and lifecycle status, queued tasks,
delivery leases, results, processed-envelope replay records, GitHub cursors,
and channel-specific state in its configured data directory. The beacon stores
its signing identity and task ledger locally.

Back up and restore these as security state, not disposable cache. Restoring
only part of the state can invalidate identity or replay assumptions. Never
copy one beacon's identity directory to another host.

## Recovery

When ordinary channels cannot authenticate, `DeadDropResolver` searches a
dedicated public recovery repository for a deterministic record. Each record
is signed by the recovery identity, sealed to one beacon, generation-numbered,
time-bounded, and constrained by the controller's complete replacement policy.

A valid record can replace transport configuration and provide a narrowed,
short-lived GitHub App installation-token lease. It cannot grant authority
outside the server's exact per-beacon policy. See [Recovery](RECOVERY.md).

## Feature boundaries

- Thirteen channel kinds are selectable; the reserved PR+SSH catalog entry is
intentionally unavailable.
- Six task kinds are accepted: `shell`, `exec`, `ping`, `sleep`, `kill`, and
`evasion`. Argument schemas and risk levels are centralized in `shared/`.
- Remote module loading is rejected across public surfaces.
- HTTP and gRPC listeners are opt-in. HTTP requires TLS; gRPC requires mTLS and
a per-beacon bearer credential.
- App private keys and recovery signing secrets are controller-only.
- Channel availability is an environment claim, not a catalog claim. Local
tests, integration tests, and live task/result qualification are reported as
separate evidence levels.

## Trust boundaries

| Boundary | Required control |
|---|---|
| Operator → controller | Operator-only API token, trusted TLS when non-loopback |
| Beacon → controller | Per-beacon bearer, trusted TLS, and mTLS/fingerprint binding for gRPC |
| Component → GitHub | Least-privilege role credential scoped to exact repositories |
| Controller → beacon | Signed task, X25519 sealing, enrolled recipient identity |
| Beacon → controller | Signed result, ownership check, replay rejection, acceptance digest |
| Recovery repo → beacon | Recovery signature, exact beacon recipient, generation and expiry checks |
| Proxy/relay → endpoints | Signed route/configuration and exact repository or certificate bindings |

For a deployment checklist and failure policy, continue with [Operations and
assurance](PRODUCTION.md).
Loading
Loading