Metadata-Version: 2.4
Name: voidremote
Version: 2.0.0
Summary: A Python SDK and toolkit for controlling Android devices over ADB (wired and wireless).
Author-email: V0IDNETWORK <ilianothingg@gmail.com>
Maintainer-email: V0IDNETWORK <ilianothingg@gmail.com>
License: MIT License
        
        <<<<<<< HEAD
        Copyright (c) 2025 V0IDNETWORK
        =======
        Copyright (c) 2026 V0IDNETWORK
        >>>>>>> 0f6ab1c0b207cd02bb93b87449cd9313e7e6e3f0
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        <<<<<<< HEAD
        =======
        
        ---
        
        Additional note: this repository intentionally contains applications that are
        vulnerable by design (see /vulnerable-apps and /attacker-box) for educational,
        isolated, self-hosted penetration-testing training purposes only. Do not
        deploy any component of /vulnerable-apps or /attacker-box on a
        publicly-reachable host or network you do not fully control.
        >>>>>>> 0f6ab1c0b207cd02bb93b87449cd9313e7e6e3f0
        
Project-URL: Homepage, https://github.com/V0IDNETWORK/VoidRemote
Project-URL: Documentation, https://github.com/V0IDNETWORK/VoidRemote/blob/main/docs/API.md
Project-URL: Repository, https://github.com/V0IDNETWORK/VoidRemote
Project-URL: Bug Tracker, https://github.com/V0IDNETWORK/VoidRemote/issues
Project-URL: Changelog, https://github.com/V0IDNETWORK/VoidRemote/blob/main/CHANGELOG.md
Project-URL: Author, https://voidnetwork.ir/
Keywords: android,adb,adb-controller,sdk,automation,testing,ci,wireless-debugging,scrcpy,mobile-automation
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: System :: Hardware
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic<3.0,>=2.7
Requires-Dist: pydantic-settings<3.0,>=2.3
Requires-Dist: platformdirs<5.0,>=4.2
Requires-Dist: typing-extensions>=4.11; python_version < "3.13"
Provides-Extra: cli
Requires-Dist: click<9.0,>=8.1.7; extra == "cli"
Requires-Dist: rich<14.0,>=13.7; extra == "cli"
Provides-Extra: gui
Requires-Dist: PySide6<6.9,>=6.7; extra == "gui"
Provides-Extra: full
Requires-Dist: voidremote[cli,gui]; extra == "full"
Provides-Extra: dev
Requires-Dist: voidremote[full]; extra == "dev"
Requires-Dist: pytest<9.0,>=8.2; extra == "dev"
Requires-Dist: pytest-asyncio<0.24,>=0.23; extra == "dev"
Requires-Dist: pytest-cov<6.0,>=5.0; extra == "dev"
Requires-Dist: pytest-mock<4.0,>=3.14; extra == "dev"
Requires-Dist: pytest-qt<5.0,>=4.4; extra == "dev"
Requires-Dist: build<2.0,>=1.2; extra == "dev"
Requires-Dist: black<25.0,>=24.4; extra == "dev"
Requires-Dist: ruff<0.5,>=0.4; extra == "dev"
Requires-Dist: mypy<2.0,>=1.10; extra == "dev"
Requires-Dist: types-requests; extra == "dev"
Requires-Dist: pre-commit<4.0,>=3.7; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs<2.0,>=1.6; extra == "docs"
Requires-Dist: mkdocs-material<10.0,>=9.5; extra == "docs"
Requires-Dist: mkdocstrings[python]<0.26,>=0.25; extra == "docs"
Dynamic: license-file

<<<<<<< HEAD
# VoidRemote

A Python interface to Android Debug Bridge (ADB).

VoidRemote wraps `adb` so you write Python instead of shell commands. It
discovers devices, manages wireless pairing and connections, and gives you
a typed `Device` object for input, file transfer, shell access, package
management, screen capture, and monitoring.

```python
from voidremote import VoidRemote

client = VoidRemote()
client.start()

device = client.devices().first()
device.tap(500, 800)
device.text("hello world")
device.screenshot("screen.png")
```

No `adb shell input tap ...` strings. No manually parsing `adb devices -l`
output. No subprocess plumbing in your code.

---

## Who this is for

- Python developers automating Android devices
- Test engineers writing device-driven test suites
- CI/CD pipelines that need to install, launch, and verify apps
- Scripts and tools that need device telemetry (battery, storage, CPU)
- Applications built on top of ADB — VoidRemote's own CLI and desktop
  GUI are themselves built on this SDK (see [Also included](#also-included))

---

## Installation

```bash
pip install voidremote
```

Requires Python 3.12+ and the `adb` binary on your `PATH` (install via
[Android Platform Tools](https://developer.android.com/tools/releases/platform-tools)).
VoidRemote shells out to your existing `adb` — it does not bundle or
replace it.

The base install is SDK-only, with no CLI or GUI dependencies pulled in:

```bash
pip install voidremote          # SDK only
pip install voidremote[cli]     # + command-line tool
pip install voidremote[gui]     # + desktop app
pip install voidremote[full]    # SDK + CLI + GUI
```

---

## Quick start

```python
from voidremote import VoidRemote

client = VoidRemote()
client.start()                       # verify adb, start the adb server

devices = client.devices()           # discover devices already visible to adb
device = devices.first()

device.tap(500, 800)
device.swipe(500, 1600, 500, 400)
device.text("hello world")
device.key_event(4)                  # KEYCODE_BACK

device.push("app-release.apk", "/sdcard/app.apk")
device.install("app-release.apk")

output = device.shell("pm list packages -3")
device.screenshot("screen.png")
```

Connecting a device that isn't already known to `adb`:

```python
from voidremote import VoidRemote

client = VoidRemote()
client.start()

# Wireless debugging, paired by the 6-digit code shown on-device
device = client.pair_and_connect(host="192.168.1.42", port=37831, code="482913")

# Already paired, just needs a TCP connection
device = client.connect("192.168.1.42")
```

Every call above runs one real `adb` command under the hood — VoidRemote
just gives it a name, a type, and a place to raise a real exception.

---

## Philosophy

VoidRemote exists to remove one layer of indirection: the one between what
you mean and the `adb` command line syntax for it.

| Instead of shelling out to...                          | You write            |
|----------------------------------------------------------|-----------------------|
| `adb shell input tap 500 800`                            | `device.tap(500, 800)` |
| `adb shell input text "hello"`                            | `device.text("hello")` |
| `adb push app.apk /sdcard/app.apk`                        | `device.push("app.apk", "/sdcard/app.apk")` |
| `adb install -r app.apk`                                   | `device.install("app.apk")` |
| `adb shell pm list packages -3`                             | `device.list_packages()` |
| `adb pair 192.168.1.42:37831 482913`                        | `client.pair(host, port, code)` |
| parsing `adb devices -l` output by hand                     | `client.devices()` |
| parsing `dumpsys battery` output by hand                     | `device.battery_level` |

Nothing here is magic — every method is a thin, validated wrapper around
one `adb` invocation. VoidRemote doesn't try to be smarter than `adb`; it
tries to be a smaller, typed surface on top of it, with input validated
against command injection before it ever reaches a shell.

---
=======
<p align="center">
  <img src="docs/banner.svg" alt="VOIDLAB — OWASP Top 10:2025 Web Penetration Testing Laboratory" width="100%" />
</p>

<h3 align="center">A self-hosted, containerized web penetration testing training range.</h3>
<p align="center">
  Live vulnerable targets · a sandboxed in-browser terminal · flag-based scoring · a real OWASP Top 10:2025 curriculum.
</p>

<p align="center">
  <a href="#quick-start">Quick Start</a> ·
  <a href="#features">Features</a> ·
  <a href="#owasp-top-102025-coverage">OWASP Coverage</a> ·
  <a href="#architecture">Architecture</a> ·
  <a href="#extending-the-lab-catalog">Extending</a> ·
  <a href="#credits">Credits</a>
</p>

---

## What is VOIDLAB?

VOIDLAB is a modular, Dockerized penetration-testing lab you run yourself: a Django 5 / DRF
backend, a React 18 + TypeScript frontend, and a set of genuinely vulnerable, isolated
containers to attack — wired together with an authenticated flag-submission workflow, a
points/leaderboard system, hint economy, and an in-browser sandboxed terminal.

It's built around the **current OWASP Top 10:2025** list (OWASP refreshed the Top 10 in late
2025 — this project tracks that update rather than the older 2021 edition), with 21 hand-written
labs spanning all ten categories. Five labs run against **live, disposable, non-privileged
containers** (SQL injection, reflected XSS, OS command injection, IDOR/BFLA, and SSRF); the
remaining labs are realistic **analysis challenges** — a genuine artifact (vulnerable code
snippet, log excerpt, encoded config) embedded in the briefing, in the same spirit as
jeopardy-style CTF "misc/crypto/forensics" categories. See [Extending the lab
catalog](#extending-the-lab-catalog) for how to turn any of those into a live target, and how to
grow the catalog past 30 labs using the exact same pattern.

## Features

- 🔐 **JWT authentication & profiles** — register, log in, track points and labs completed.
- 🧪 **21 structured labs** across all ten OWASP Top 10:2025 categories, easy → insane.
- 🎯 **5 live, isolated vulnerable-app containers** (SQLi, XSS, Command Injection, IDOR/BFLA, SSRF), each its own non-root, capability-dropped Docker service.
- 🖥️ **Sandboxed in-browser terminal** over WebSocket, proxying an allowlisted recon toolkit into an isolated, non-privileged `attacker-box` container — enforced server-side, twice over, never a raw shell.
- 🚩 **Flag submission** with idempotent scoring, per-hint point penalties, and a full attempt/audit trail.
- 💡 **Tiered hints** that cost points, plus **admin/instructor-only full solutions** — gated server-side by role, not just hidden in the UI.
- 🏆 **Live leaderboard**, cached briefly for snappy polling.
- 🎨 **Dark, cyberpunk-inspired UI** — Tailwind v4 + a hand-built shadcn-style component set, Chakra Petch/Inter/JetBrains Mono type system, a 4-color semantic signal palette (violet/cyan/amber/crimson) instead of one flat neon accent.
- 🐳 **One-command Docker Compose stack**: frontend, backend, Postgres, Redis, attacker-box, and every vulnerable-app target.

## OWASP Top 10:2025 coverage

| Code | Category | Labs |
|------|----------|------|
| A01 | Broken Access Control (now includes IDOR & SSRF) | Profile Peeper (IDOR) · Admin By Accident (BFLA) · Metadata Reach (SSRF) |
| A02 | Security Misconfiguration | Debug Left On · Bucket Left Open |
| A03 | Software Supply Chain Failures | Typosquat Trap · Unsigned Update |
| A04 | Cryptographic Failures | Weak Hash Cracker · None Alg JWT |
| A05 | Injection | SQL Injection: Login Bypass · Reflected XSS: Cookie Heist · OS Command Injection |
| A06 | Insecure Design | Negative Quantity · No Rate Limit, No Problem |
| A07 | Authentication Failures | Session Fixation · Brute-Forceable Login |
| A08 | Software or Data Integrity Failures | Insecure Deserialization · Tampered Update, Take Two |
| A09 | Security Logging and Alerting Failures | Silent Intruder |
| A10 | Mishandling of Exceptional Conditions (new for 2025) | Fail Open · Race Condition Redeem |

Run `python manage.py seed_labs` (done automatically on container start) to load the full
catalog with hints and solutions.

## Quick start

**Prerequisites:** Docker + Docker Compose. Nothing else needs to be installed locally.

```bash
git clone https://github.com/V0IDNETWORK/voidlab.git
cd voidlab
cp .env.example .env    
docker-compose up --build
```

Then open:

| Service | URL |
|---|---|
| Frontend | http://localhost:5173 |
| Backend API | http://localhost:8000/api/v1/ |
| API docs (Swagger) | http://localhost:8000/api/v1/docs/ |
| Django admin | http://localhost:8000/admin/ |
| sqli-lab target | http://localhost:8081 |
| xss-lab target | http://localhost:8082 |
| cmdi-lab target | http://localhost:8083 |
| idor-lab target | http://localhost:8084 |
| ssrf-lab target | http://localhost:8085 |

On first boot the backend container automatically runs migrations, seeds the OWASP category +
lab catalog, and (if `DJANGO_SUPERUSER_USERNAME`/`DJANGO_SUPERUSER_PASSWORD` are set in `.env`)
creates an admin account you can use to view hint/solution content and the Django admin.

> **Note on migrations:** this repo generates Django migrations at container startup
> (`python manage.py makemigrations` runs before `migrate` in `backend/entrypoint.sh`) rather
> than shipping pre-committed migration files, since they weren't generated against a live
> Django install when this project was authored. For a real production deployment, run
> `makemigrations` once yourself, commit the resulting files, and remove that line from the
> entrypoint so schema changes are explicit and reviewable like any other code change.
>>>>>>> 0f6ab1c0b207cd02bb93b87449cd9313e7e6e3f0

## Architecture

```
<<<<<<< HEAD
Your application
       │
       ▼
voidremote (SDK)  ──  Device, VoidRemote, PairingSession
       │
       ▼
adb executable    ──  the real Android Debug Bridge binary
       │
       ▼
Android device    ──  over USB or Wireless Debugging
```

Internally, the SDK is layered:

```
voidremote.api            stable public surface (this is what you import)
    │
voidremote.controllers    composition root — wires services together
    │
voidremote.services       device discovery, input, monitoring
    │
voidremote.adb            subprocess execution, output parsing
    │
adb binary
```

Only `voidremote.api` (re-exported at the top level, `from voidremote import
...`) is a stable, versioned surface. Everything below it — `adb`,
`services`, `controllers`, `models` — is an internal implementation detail
that can change between minor versions without notice.

---

## API design

### `VoidRemote` — the client

```python
from voidremote import VoidRemote

client = VoidRemote()
client.start()

client.devices()                          # -> DeviceList
client.device(serial)                     # -> Device
client.connect(host, port=5555)           # -> Device
client.pair(host, port, code)             # -> PairingSession
client.pair_and_connect(host, port, code) # -> Device
client.auto_reconnect()                   # -> DeviceList
```

Also usable as a context manager, which starts on entry and stops
background monitoring on exit:

```python
with VoidRemote() as client:
    for device in client.devices():
        print(device.name, device.battery_level)
```

### `Device` — everything scoped to one device

```python
device.tap(x, y)
device.swipe(x1, y1, x2, y2)
device.text("hello")
device.key_event(keycode)

device.shell("getprop ro.build.version.release")

device.push(local, remote)
device.pull(remote, local)
device.list_dir("/sdcard")

device.install(apk_path)
device.uninstall(package)
device.list_packages()
device.is_installed(package)

device.screenshot(output_path)
device.screenrecord()

device.reboot()
device.monitor(interval=2.0, callback=on_snapshot)
```

Input methods return `self`, so they chain:

```python
device.tap(500, 800).text("hello").key_event(66)  # tap, type, press Enter
```

### `DeviceList` — what `client.devices()` returns

```python
devices = client.devices()
devices.first()          # -> Device, raises NoDevicesError if empty
devices.get(serial)       # -> Device, raises DeviceNotFoundError
devices.online()          # -> DeviceList filtered to online devices
len(devices)
for device in devices: ...
```

### `PairingSession` — wireless debugging setup

```python
session = client.pair(host="192.168.1.42", port=37831, code="482913")
session.pair()             # perform the handshake
device = session.connect() # then connect on the regular ADB port
```

### Exceptions

Everything VoidRemote raises is a `VoidRemoteError`:

```python
from voidremote import VoidRemoteError, DeviceNotFoundError, NoDevicesError, PairingError

try:
    device = client.devices().first()
except NoDevicesError:
    print("No devices connected.")
except VoidRemoteError as exc:
    print(f"Something went wrong: {exc}")
```

`AdbNotAvailableError`, `AdbTimeoutError`, `AdbCommandError`,
`DeviceNotFoundError`, `NoDevicesError`, `PairingError`, `ConnectionError`,
and `InvalidArgumentError` all subclass it.

### Async

`AsyncVoidRemote` mirrors the sync API as coroutines. `adb` is a
subprocess-based CLI, not a socket protocol VoidRemote speaks directly, so
this runs the same synchronous code via `asyncio.to_thread` rather than
native async I/O — which is enough to keep your event loop unblocked, and
enough to run many devices concurrently with `asyncio.gather`:

```python
import asyncio
from voidremote import AsyncVoidRemote

async def main():
    async with AsyncVoidRemote() as client:
        devices = await client.devices()
        await asyncio.gather(*(d.tap(500, 800) for d in devices))

asyncio.run(main())
```

---

## Examples

Discover and print info for every connected device:

```python
from voidremote import VoidRemote

with VoidRemote() as client:
    for device in client.devices():
        print(f"{device.name}  {device.android_version}  {device.battery_level}%")
```

Install an APK on every connected device:

```python
from voidremote import VoidRemote

with VoidRemote() as client:
    for device in client.devices().online():
        device.install("app-release.apk")
```

Take a screenshot from a specific device:

```python
from voidremote import VoidRemote

client = VoidRemote()
client.start()
client.device("192.168.1.42:5555").screenshot("shot.png")
```

Run a shell command and use the output:

```python
device = client.devices().first()
version = device.shell("getprop ro.build.version.release")
print(f"Android {version}")
```

Poll battery and memory in the background:

```python
def on_snapshot(snapshot):
    print(f"CPU {snapshot.cpu_usage:.0f}%  RAM {snapshot.ram_usage_percent:.0f}%  "
          f"Battery {snapshot.battery_level}%")

device = client.devices().first()
device.monitor(interval=2.0, callback=on_snapshot)
```

Handle errors explicitly:

```python
from voidremote import VoidRemote, NoDevicesError, AdbNotAvailableError

try:
    client = VoidRemote()
    client.start()
    device = client.devices().first()
except AdbNotAvailableError:
    print("adb isn't installed or isn't on PATH.")
except NoDevicesError:
    print("adb is running, but no device is connected.")
```

---

## Security

Every device path, package name, host, port, and pairing code is validated
before use, and shell arguments are checked against a small blocklist of
injection characters (`; & | \` $ < > \`) and rejected outright rather than
escaped-and-hoped. See `voidremote.utils.security` — it's a small module,
worth reading if you're deciding whether to trust this with untrusted
input.

---

## Also included

The `voidremote` repository also ships two applications built entirely on
top of this SDK — neither adds anything to the SDK's public API, both are
optional installs.

**CLI** (`pip install voidremote[cli]`) — a `voidremote` command covering
device discovery, pairing, input, file transfer, package management,
shell access, and monitoring, with `--json` output for scripting. See
[docs/CLI.md](docs/CLI.md).

**Desktop GUI** (`pip install voidremote[gui]`) — a PySide6 application
(`voidremote-gui`) with a device dashboard, embedded shell, file manager,
and live monitoring graphs. See [docs/GUI.md](docs/GUI.md).

Further reading: [docs/API.md](docs/API.md) for the full API reference,
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for how the layers fit
together, [CONTRIBUTING.md](CONTRIBUTING.md) to work on VoidRemote itself.

---

## Requirements

- Python 3.12 or later
- `adb` (Android SDK Platform Tools) on `PATH`
- An Android device with USB debugging or Wireless Debugging enabled

Tested on Linux, macOS, and Windows.

---

## License

MIT — see [LICENSE](LICENSE).

## Author

**V0IDNETWORK** — an ongoing, open research effort to document, rigorously
and accurately, how the modern Internet's circumvention and surveillance
technologies actually work at the protocol level, in support of a more
open and resilient Internet.

[GitHub](https://github.com/V0IDNETWORK) ·
[Website](https://voidnetwork.ir/) ·
[LinkedIn](https://www.linkedin.com/in/ilianothing) ·
[Instagram](https://www.instagram.com/ilianothing) ·
[YouTube](https://youtube.com/@locailife) ·
[TryHackMe](https://tryhackme.com/p/ilianothingg) ·
[Medium](https://medium.com/@ilianothingg) ·
[Telegram](https://t.me/voidxMaster) ·
[ilianothingg@gmail.com](mailto:ilianothingg@gmail.com)
=======
voidlab/
├── docker-compose.yml        # orchestrates every service below
├── .env.example
├── backend/                  # Django 5 + DRF + Channels
│   ├── config/                #   settings, URLs, ASGI (HTTP + WebSocket)
│   └── apps/
│       ├── core/               #   health check, request-ID middleware, JWT-for-WS auth
│       ├── accounts/            #   custom user model, JWT auth, profile
│       ├── labs/                #   categories, labs, hints, solutions, submissions, scoring
│       ├── leaderboard/          #   cached global ranking
│       └── terminal/             #   WebSocket consumer → attacker-box proxy
├── frontend/                 # React 18 + TS + Vite + Tailwind v4 + Zustand
│   └── src/
│       ├── components/ui/       #   hand-built shadcn-style primitives
│       ├── components/layout/    #   navbar, auth guard
│       ├── store/                #   auth + labs zustand stores
│       └── pages/                #   landing, auth, dashboard, labs, terminal, leaderboard
├── attacker-box/              # isolated, non-root command-runner behind the terminal
├── vulnerable-apps/
│   ├── sqli-lab/                #   Flask + SQLite, string-concatenated login query
│   ├── xss-lab/                  #   Flask, reflected/unescaped search + local cookie collector
│   ├── cmdi-lab/                  #   Flask, os.popen() ping tool
│   ├── idor-lab/                   #   Flask, IDOR + BFLA in one app
│   └── ssrf-lab/                    #   Flask, server-side fetch + loopback metadata service
└── docs/
```

### Network segmentation

Two Docker networks: `voidlab_core` (frontend, backend, Postgres, Redis) and `voidlab_targets`
(attacker-box + every vulnerable-app container). The backend joins both, but **only** to reach
`attacker-box` for the terminal proxy — it never runs `subprocess`/`os.system` against a target
itself and never mounts the Docker socket. Every lab/attacker-box container runs as a non-root
user with `cap_drop: [ALL]` (plus a narrow, explicit `cap_add` only where a tool genuinely needs
it, e.g. `NET_RAW` for `ping` in `cmdi-lab`).

### The sandboxed terminal, honestly

The in-browser terminal is a real, working feature — not a simulation — but it is scoped
deliberately: it proxies a **fixed allowlist** of read-only recon tools (`curl`, `nmap`, `dig`,
`whoami`, `id`, `ls`, `cat`, `pwd`, `echo`, `nslookup`, `sqlmap`, `nikto`) into the isolated
`attacker-box` container, enforced independently in **two** places (the Django consumer and the
exec server itself), with a hard per-command timeout and output cap. It is appropriate for a
**self-hosted** training lab you run yourself. It is **not** hardened for exposing to the public
internet as a multi-tenant SaaS — that would need a fresh, ephemeral, per-session sandbox (e.g.
gVisor or Firecracker microVMs) instead of one shared `attacker-box`, which is a meaningful next
step, not a checkbox.

## Extending the lab catalog

Every lab lives as one entry in `backend/apps/labs/management/commands/seed_labs.py`'s
`LAB_CATALOG` list. To add a new lab:

1. Add a new dict to `LAB_CATALOG` — `cat` (category code), `title`, `difficulty`, `points`,
   `summary`, `briefing`, `objective`, `flag`, `hints`, `solution`, and either a `target_app` +
   `target_path` (if it targets a live container) or leave those blank for a self-contained
   analysis challenge.
2. Re-run `python manage.py seed_labs` (idempotent — safe to re-run any time).
3. If it needs a **new live container**: copy the shape of any folder under `vulnerable-apps/`,
   add it as a service to `docker-compose.yml` on the `voidlab_targets` network, add its URL to
   `VULNERABLE_APP_URLS` in `backend/config/settings.py`, and point `target_app` at its key.

This repository ships 21 labs; the pattern above is identical for lab #22 through #30+.

## Tech stack

**Frontend:** React 18, TypeScript, Vite, Tailwind CSS v4, hand-built shadcn-style components, React Router 6, Zustand, Axios, lucide-react, react-markdown.
**Backend:** Django 5.2 LTS, Django REST Framework, SimpleJWT, Django Channels (WebSocket), drf-spectacular (OpenAPI docs), PostgreSQL 16, Redis 7.
**Infra:** Docker, Docker Compose, nginx (frontend static serving), Daphne (ASGI server).


## Honest scope notes

This is a real, working platform, not a mockup — but it's worth being precise about what
"working" means here:

- 5 of the 21 labs run against **live** containers you can actually attack end-to-end; the rest
  are analysis-style challenges (see above) rather than live-exploitable services.
- Migrations are generated at container start rather than committed (see the note under [Quick
  start](#quick-start)) — fine for spinning the stack up, not a substitute for committed
  migrations in a real deployment.
- The terminal's sandboxing is real but scoped to a **self-hosted, single-tenant** use case; see
  [Architecture](#architecture) for what a public multi-tenant version would additionally need.
## License

This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details.

## Credits

Built by **V0IDNETWORK** — an open research effort on Internet circumvention & surveillance technologies.

- **GitHub**: [V0IDNETWORK](https://github.com/V0IDNETWORK)
- **Website**: [voidnetwork.ir](http://voidnetwork.ir/)
- **LinkedIn**: [ilianothing](https://www.linkedin.com/in/ilianothing)
- **Instagram**: [@ilianothing](https://www.instagram.com/ilianothing)
- **TryHackMe**: [ilianothingg](https://tryhackme.com/p/ilianothingg)
- Contact: +989928102005 · [ilianothingg@gmail.com](mailto:ilianothingg@gmail.com)

<p align="center"><b>∆ Join VOID ∆</b></p>

>>>>>>> 0f6ab1c0b207cd02bb93b87449cd9313e7e6e3f0
