π Web Dashboard & REST/WebSocket API Reference
Raspiducky embeds a lightweight, hardened web application directly into its single Go binary using go:embed. Users can monitor hardware state, reconfigure composite USB Gadget profiles without rebooting, tune typing speed and keyboard layout, edit payloads, and stream execution logs in real time.
π¨ Single-Page Application (SPA) Features
- Composite Gadget Profile Manager: Independently toggle HID Keyboard, HID Mouse, Mass Storage (Flash Drive or CD-ROM, writable or read-only), Windows RNDIS, Linux/macOS CDC ECM, and CDC ACM Serial interfaces at runtime.
- Live Hardware Endpoint Guard: Displays
usedEndpoints / maxEndpointsdirectly from kernel DebugFS (hw_params) and blocks invalid combinations before touching ConfigFS. - Typing Speed & Layout Controls: Select regional keyboard translation (
US,ES,DE,FR) and inter-keystroke delay (10msdefault for universal PC & 60Hz console stability, or0msfor raw burst speed). - Payload Editor & Library: Create, edit, run, and persist DuckyScript (
.ducky/.txt) and JavaScript (.js) payloads in the browser. - Live Execution Console & Instant Stop: Streams real-time logs over WebSocket and interrupts active scripts and
/dev/hidg*writes immediately viaStop. - Host Keyboard LED Indicators: Reflects live
NumLock,CapsLock, andScrollLockstatus reported by the connected USB host.
π Built-In Web & API Security
- Content-Security-Policy & Frame Protection: Static UI assets are served with
Content-Security-Policy(default-src 'self',object-src 'none',frame-ancestors 'none'),X-Frame-Options: DENY, andX-Content-Type-Options: nosniff. - Same-Origin / CSRF Protection: Mutating
POSTandDELETEroutes validateSec-Fetch-SiteandOriginheaders against the targetHost, blocking cross-origin browser attacks (403 Forbidden) while allowing local CLI /curlautomation (which omits browserOriginheaders). - Bounded Request Bodies: JSON request bodies are capped at
1 MiBviahttp.MaxBytesReader.
π Real-Time WebSocket API (/api/ws)
The WebSocket endpoint streams live state transitions and execution logs, and delivers an atomic initial snapshot (led_state, gadget_status, and any active job_status) immediately upon connection or reconnect:
Event Envelope
{
"type": "log | led_state | gadget_status | job_status",
"level": "INFO | WARN | ERROR",
"source": "ENGINE | JS | DUCKY | GADGET",
"message": "Human-readable event message",
"payload": {}
}
Event Types
1. Log Broadcast (type: "log")
2. Host LED State (type: "led_state")
3. Gadget Status (type: "gadget_status")
{
"type": "gadget_status",
"payload": {
"deployed": true,
"activeFunctions": ["hid.usb0", "hid.usb1"],
"udc": "20980000.usb",
"maxEndpoints": 7,
"usedEndpoints": 3,
"endpointCosts": {
"ep0": 1,
"keyboard": 1,
"mouse": 1,
"storage": 2,
"rndis": 3,
"ecm": 3,
"serial": 3
},
"config": {
"keyboard": true,
"mouse": true,
"storage": false,
"storageCdrom": false,
"storageReadOnly": false,
"rndis": false,
"ecm": false,
"serial": false,
"vendorId": "0x1d6b",
"productId": "0x0104",
"manufacturer": "Raspiducky",
"product": "USB Composite Gadget",
"serialNumber": "RPD-0001",
"storageSizeMb": 64,
"keyboardLayout": "US",
"typingDelayMs": 10
}
}
}
4. Job Execution Status (type: "job_status")
status transitions through "running", "completed", "stopped", or "failed":
{
"type": "job_status",
"payload": {
"id": "job-1762817000123",
"name": "recon_payload.js",
"type": "javascript",
"status": "running",
"startedAt": "2026-11-11T00:10:00Z"
}
}
π‘ REST API Reference
| Endpoint | Method | Description |
|---|---|---|
/api/gadget |
GET |
Retrieve active USB gadget configuration, UDC, and endpoint usage |
/api/gadget |
POST |
Validate, persist, and deploy USB gadget parameters |
/api/scripts |
GET |
List all saved payload scripts in persistent storage |
/api/scripts |
POST |
Save or update a payload script (201 Created) |
/api/scripts/{name} |
DELETE |
Delete a payload script (204 No Content) |
/api/job |
GET |
Retrieve current or most recent script job status |
/api/run |
POST |
Trigger execution of an inline script payload |
/api/stop |
POST |
Immediately interrupt active script execution |
GET /api/gadget
Returns the active GadgetStatus, including maxEndpoints, usedEndpoints, endpointCosts, and persisted config.
Response (200 OK)
{
"deployed": true,
"activeFunctions": ["hid.usb0", "hid.usb1"],
"udc": "20980000.usb",
"maxEndpoints": 7,
"usedEndpoints": 3,
"endpointCosts": {
"ep0": 1,
"keyboard": 1,
"mouse": 1,
"storage": 2,
"rndis": 3,
"ecm": 3,
"serial": 3
},
"config": {
"keyboard": true,
"mouse": true,
"storage": false,
"storageCdrom": false,
"storageReadOnly": false,
"rndis": false,
"ecm": false,
"serial": false,
"vendorId": "0x1d6b",
"productId": "0x0104",
"manufacturer": "Raspiducky",
"product": "USB Composite Gadget",
"serialNumber": "RPD-0001",
"storageSizeMb": 64,
"keyboardLayout": "US",
"typingDelayMs": 10
}
}
POST /api/gadget
Validates, saves (gadget_config.json), and applies new ConfigFS settings. Returns the updated GadgetStatus.
Request Schema
{
"keyboard": true,
"mouse": true,
"storage": false,
"storageCdrom": false,
"storageReadOnly": false,
"rndis": false,
"ecm": true,
"serial": false,
"vendorId": "0x1d6b",
"productId": "0x0104",
"manufacturer": "Custom USB Vendor",
"product": "Custom Composite Device",
"serialNumber": "SN-994021",
"storageSizeMb": 128,
"keyboardLayout": "ES",
"typingDelayMs": 10
}
Validation Rules
vendorIdandproductIdmust be 4-digit hexadecimal strings prefixed with0x(e.g.,"0x1d6b").manufacturer,product, andserialNumbermust be non-empty.- At least one USB function (
keyboard,mouse,storage,rndis,ecm, orserial) must betrue. - Total endpoints (
1forEP0plus enabled function costs) must not exceedmaxEndpointswhen reported by the UDC.
GET /api/scripts
Lists all saved payload scripts residing in /var/lib/raspiducky/scripts.
Response (200 OK)
[
{
"name": "windows_notepad.ducky",
"type": "duckyscript",
"content": "DELAY 1000\nGUI r\nDELAY 500\nSTRINGLN notepad.exe\n",
"updatedAt": "2026-11-11T00:15:30Z"
},
{
"name": "mouse_jiggler.js",
"type": "javascript",
"content": "mouseMove(10, 0);\ndelay(200);\nmouseMove(-10, 0);\n",
"updatedAt": "2026-11-11T00:20:00Z"
}
]
POST /api/scripts
Creates or updates a script file in persistent storage. Script filenames are strictly sanitized against path traversal.
Request Schema
{
"name": "payload_test.js",
"type": "javascript",
"content": "layout('es');\ntype('Β‘Hola Mundo!\\n');"
}
Response (201 Created)
DELETE /api/scripts/{name}
Deletes a saved script file from persistent storage. Returns 204 No Content on success or 404 Not Found if the script does not exist.
GET /api/job
Returns the active or most recently completed JobStatus object (200 OK), or null if no job has been executed since daemon startup.
{
"id": "job-1762817000123",
"name": "payload_test.js",
"type": "javascript",
"status": "completed",
"startedAt": "2026-11-11T00:25:00Z",
"finishedAt": "2026-11-11T00:25:02Z"
}
POST /api/run
Compiles/validates and starts immediate execution of a DuckyScript or JavaScript payload. Optional layout and typingDelayMs fields override the saved defaults for that run ("typingDelayMs": 0 explicitly selects 0ms burst mode). Invalid DuckyScript returns 400 Bad Request with line N: details before starting a job.
Request Schema
{
"name": "custom_job",
"type": "duckyscript",
"script": "GUI r\nDELAY 500\nSTRINGLN notepad.exe",
"layout": "ES",
"typingDelayMs": 10
}
Response (200 OK)
POST /api/stop
Immediately cancels the running script context, interrupts Goja execution (vm.Interrupt), wakes any blocked /dev/hidg* write, and releases held keys/buttons.
Response (200 OK)
π» Remote Automation with curl
1. Fetch Device & Endpoint Status
2. Deploy Keyboard + Mass Storage Profile
curl -fsSL -X POST http://192.168.1.50:8000/api/gadget \
-H "Content-Type: application/json" \
-d '{
"keyboard": true,
"mouse": false,
"storage": true,
"rndis": false,
"ecm": false,
"serial": false,
"vendorId": "0x05ac",
"productId": "0x0221",
"manufacturer": "Apple Inc.",
"product": "Keyboard & Mass Storage",
"serialNumber": "APL-88301",
"storageSizeMb": 128,
"keyboardLayout": "US",
"typingDelayMs": 10
}'
3. Execute a Payload Remotely (with Explicit 0ms Burst Delay)
curl -fsSL -X POST http://192.168.1.50:8000/api/run \
-H "Content-Type: application/json" \
-d '{
"name": "remote_exec",
"type": "javascript",
"script": "press(\"GUI R\"); delay(500); type(\"calc.exe\\n\");",
"layout": "US",
"typingDelayMs": 0
}'