Pwnote engagement file
AI agent skills for Pwnote Pentest Notebook
npx -y skills add Pwnote/skills --skill pwnote-engagement-fileAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 14 days oldThe repository was created 14 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Create or validate a pwnote engagement import/export JSON file. Use when the user wants to generate, edit, or verify a pwnote engagement file for data transfer between pwnote instances. The file bundles an entire pentest engagement — metadata, notebook documents, code/host/credential blocks, findings with CVSS/cwe/cve, attack-path boards, and activity history. Also use when the user asks how to structure such a file, needs a template, or wants to programmatically generate one from external tooling.
SKILL.md
15.6 KB, as published. Nobody here has run it
Security
This skill describes the engagement file schema for data transfer between pwnote instances. Follow these rules:
- Never output real credential
secretvalues anywhere — use<REDACTED>as placeholder - Never log, echo, or print plaintext secrets
- Treat
requestBody,requestHeaders,responseBodyfields as potentially sensitive — redact before sharing externally - The
secretfield in credential blocks is populated from user-provided data, never generated by the agent
Installation
npx skills add Pwnote/skills
Pwnote Engagement File Format
Reference for creating or editing pwnote engagement import/export JSON files. A valid file contains all data for one pentest engagement and can be imported via Settings → Import or the workspace Import button.
File Structure
{
"engagement": { ... },
"docs": [ ... ],
"blocks": [ ... ],
"findings": [ ... ],
"boards": [ ... ],
"boardNodes": [ ... ],
"boardEdges": [ ... ],
"activity": [ ... ]
}
All top-level keys are required but may be empty arrays.
Field Reference
engagement (object)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Engagement name, e.g. "Q4_External_2026" |
client | string | yes | Client name, e.g. "Acme Corp" |
testType | string | yes | One of: "black-box", "grey-box", "white-box" |
scope | string[] | yes | IPs, domains, CIDRs, app URLs |
roe | string | no | Rules of engagement as free text |
startDate | string | yes | ISO date "YYYY-MM-DD" |
endDate | string | yes | ISO date "YYYY-MM-DD" |
testers | string[] | yes | Operator names/handles |
archived | boolean | yes | false for new engagements |
Generated fields (omit — set on import): id, createdAt, updatedAt.
docs (array of objects)
| Field | Type | Required | Description |
|---|---|---|---|
title | string | yes | Doc name, e.g. "01_Recon" |
order | number | yes | Sort order within engagement |
parentId | string | no | Parent doc ID for folder nesting |
folder | boolean | no | true if this doc is a folder |
Generated fields: id, engagementId, createdAt, updatedAt.
blocks (array of objects)
Each block has these base fields plus type-specific fields:
Base fields (all block types):
| Field | Type | Required | Description |
|---|---|---|---|
type | string | yes | Block type discriminator (see below) |
docId | string | yes | Must match a doc id in the file |
order | number | yes | Sort order within doc |
tags | string[] | no | Tag labels, e.g. ["nmap", "discovery"] |
Generated fields: id.
Type-specific fields:
"heading" — Section header
| Field | Type | Required | Description |
|---|---|---|---|
level | number | yes | 1, 2, or 3 |
text | string | yes | Heading text |
Use level: 1 for document titles, level: 2 for major sections, level: 3 for sub-sections. Always use a mix of levels for structure — never use only level 1.
"paragraph" — Plain text
| Field | Type | Required | Description |
|---|---|---|---|
text | string | yes | Paragraph content |
"markdown" — Rich text block
| Field | Type | Required | Description |
|---|---|---|---|
markdown | string | yes | Markdown content |
"code" — Code snippet
| Field | Type | Required | Description |
|---|---|---|---|
language | string | yes | e.g. "bash", "python3", "rust", "go", "javascript", "typescript", "sql", "yaml" |
code | string | yes | Code content |
"command-output" — Shell command and its output
| Field | Type | Required | Description |
|---|---|---|---|
command | string | yes | The command run |
output | string | yes | Command output text |
timestamp | string | no | ISO timestamp |
"host" — Host/asset entry
| Field | Type | Required | Description |
|---|---|---|---|
ip | string | yes | IP address |
hostname | string | no | DNS name |
os | string | no | Operating system |
ports | string[] | yes | Port list, e.g. ["22/tcp", "80/tcp", "443/tcp"] |
notes | string | no | Free-text notes |
"credential" — Credential (sensitive). The secret field must use <REDACTED> when demonstrating — never output real values.
| Field | Type | Required | Description |
|---|---|---|---|
username | string | yes | Username |
secret | string | yes | <REDACTED> in examples; real values come from user-provided data only |
secretType | string | yes | One of: "password", "hash", "token", "key" |
source | string | no | Where credential was found |
sensitive | boolean | yes | Always true |
"screenshot" — Image evidence
| Field | Type | Required | Description |
|---|---|---|---|
dataUrl | string | no | Base64 data URL of image |
caption | string | no | Image caption |
"checklist" — Task checklist
| Field | Type | Required | Description |
|---|---|---|---|
title | string | yes | Checklist title |
items | array | yes | Array of { id: string, text: string, done: boolean } |
"timeline" — Timeline event
| Field | Type | Required | Description |
|---|---|---|---|
timestamp | string | yes | ISO datetime |
event | string | yes | Event description |
actor | string | no | Who performed the action |
"table" — Data table
| Field | Type | Required | Description |
|---|---|---|---|
headers | string[] | yes | Column headers |
rows | array | yes | Array of string arrays (cells) |
"separator" — Visual divider
No extra fields beyond base.
"http-request" — HTTP request/response pair
| Field | Type | Required | Description |
|---|---|---|---|
method | string | yes | HTTP method: "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS" |
url | string | yes | Request URL |
requestHeaders | string | yes | Raw request headers (one per line) |
requestBody | string | yes | Request body |
responseStatus | number | yes | HTTP status code (0 if no response) |
responseHeaders | string | yes | Raw response headers (one per line) |
responseBody | string | yes | Response body |
"finding" — Linked finding (references a finding by ID)
| Field | Type | Required | Description |
|---|---|---|---|
findingId | string | yes | Must match a finding id in the file |
findings (array of objects)
| Field | Type | Required | Description |
|---|---|---|---|
title | string | yes | Finding title |
severity | string | yes | One of: "critical", "high", "medium", "low", "info" |
cvssScore | number | no | 0.0–10.0 |
cvssVector | string | no | CVSS vector string |
cwe | string | no | CWE identifier, e.g. "CWE-79" |
cve | string | no | CVE identifier, e.g. "CVE-2024-12345" |
affectedAssets | string[] | yes | Affected hosts/URLs |
description | string | yes | Vulnerability description |
poc | string | yes | Proof of concept |
remediation | string | yes | Fix guidance |
references | string[] | yes | URLs to references |
status | string | yes | One of: "draft", "confirmed", "fixed", "accepted-risk", "needs-retest" |
retestResult | string | no | Outcome of retest |
tags | string[] | yes | Tag labels |
Generated fields: id, engagementId, createdAt, updatedAt.
boards (array of objects)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Board name, e.g. "Topology" |
kind | string | yes | One of: "topology", "killchain", "planning", "forensics", "retest", "post-exploitation", "custom" |
locked | boolean | no | true to lock board from edits |
Generated fields: id, engagementId, createdAt, updatedAt.
boardNodes (array of objects)
| Field | Type | Required | Description |
|---|---|---|---|
refType | string | yes | One of: "host", "finding", "credential", "freeform" |
refId | string | no | Links to block/finding ID (null for freeform) |
x | number | yes | Flow canvas X position |
y | number | yes | Flow canvas Y position |
data | object | no | Extra node data (label for freeform, ip/ports for host, etc.) |
boardId | string | yes | Must match a board id in the file |
Generated fields: id.
boardEdges (array of objects)
| Field | Type | Required | Description |
|---|---|---|---|
source | string | yes | Source boardNode id |
target | string | yes | Target boardNode id |
label | string | no | Edge label (e.g. "credential" for cred edges) |
boardId | string | yes | Must match a board id in the file |
Generated fields: id.
activity (array of objects)
| Field | Type | Required | Description |
|---|---|---|---|
actor | string | yes | Who performed the action |
kind | string | yes | Activity kind, e.g. "engagement.create", "block.create", "finding.status" |
message | string | yes | Human-readable description |
meta | object | no | Extra metadata |
Generated fields: id, engagementId, timestamp.
ID Linking Rules
IDs in export files are local references. The import process regenerates all IDs but preserves the relationship graph by remapping foreign keys automatically. Use any ID pattern you like (e.g. tmp_doc_recon, tmp_f_xss, tmp_bn_host1).
All cross-references MUST point to IDs defined within the same JSON file. The import remaps them to the newly generated IDs so links survive the import intact.
| Foreign Key | Points To | Field Location |
|---|---|---|
block.docId | doc id | every block |
block.findingId | finding id | finding-type blocks only |
boardNode.boardId | board id | every boardNode |
boardNode.refId | block id or finding id | host/finding/credential nodes |
boardEdge.source | boardNode id | every boardEdge |
boardEdge.target | boardNode id | every boardEdge |
boardEdge.boardId | board id | every boardEdge |
Freeform nodes have refId: null (no link to any block/finding).
Node Linking Example
To display a host and linked finding on a topology board:
{
"docs": [{ "id": "tmp_doc_recon", "title": "01_Recon", "order": 0 }],
"blocks": [
{
"id": "tmp_b_host1", "docId": "tmp_doc_recon", "order": 0, "tags": [],
"type": "host", "ip": "10.0.0.1", "hostname": "web.example.com",
"os": "Ubuntu 22.04", "ports": ["22/tcp", "80/tcp", "443/tcp"]
},
{
"id": "tmp_b_finding1", "docId": "tmp_doc_recon", "order": 1, "tags": ["web"],
"type": "finding", "findingId": "tmp_f_xss"
}
],
"findings": [
{
"id": "tmp_f_xss", "title": "Reflected XSS",
"severity": "high", "cvssScore": 6.1, "...": "..."
}
],
"boards": [
{ "id": "tmp_brd_topology", "name": "Topology", "kind": "topology" }
],
"boardNodes": [
{
"id": "tmp_bn_host1", "boardId": "tmp_brd_topology",
"refType": "host", "refId": "tmp_b_host1",
"x": 100, "y": 100,
"data": { "ip": "10.0.0.1", "hostname": "web.example.com", "ports": ["22/tcp", "80/tcp", "443/tcp"] }
},
{
"id": "tmp_bn_finding1", "boardId": "tmp_brd_topology",
"refType": "finding", "refId": "tmp_f_xss",
"x": 350, "y": 100,
"data": { "title": "Reflected XSS", "severity": "high", "cvssScore": 6.1 }
}
],
"boardEdges": [
{
"id": "tmp_be_1", "boardId": "tmp_brd_topology",
"source": "tmp_bn_host1", "target": "tmp_bn_finding1",
"label": "exploits"
}
]
}
Key rules for node data:
hostnodes:datamust includeip,hostname,portsfindingnodes:datamust includetitle,severity,cvssScorecredentialnodes:datamust includeusername,secretTypefreeformnodes:datamust includelabel(display text)- Edges between credential and host nodes should use
label: "credential"for visual styling
Example: Minimal Engagement
{
"engagement": {
"name": "External Pentest Q4",
"client": "Example Corp",
"testType": "grey-box",
"scope": ["10.0.0.0/24", "app.example.com"],
"roe": "Testing window: 09-18 local.\nExclusions: production DB.",
"startDate": "2026-07-21",
"endDate": "2026-08-04",
"testers": ["operator"],
"archived": false
},
"docs": [
{ "id": "tmp_doc_recon", "title": "01_Recon", "order": 0, "engagementId": "tmp_eng" },
{ "id": "tmp_doc_exploit", "title": "02_Exploitation", "order": 1, "engagementId": "tmp_eng" }
],
"blocks": [
{
"id": "tmp_b_host1", "docId": "tmp_doc_recon", "order": 0, "tags": [],
"type": "host", "ip": "10.0.0.1", "hostname": "web.example.com", "os": "Ubuntu 22.04",
"ports": ["22/tcp", "80/tcp", "443/tcp"]
},
{
"id": "tmp_b_finding1", "docId": "tmp_doc_exploit", "order": 0, "tags": ["web"],
"type": "finding", "findingId": "tmp_f_xss"
},
{
"id": "tmp_b_sep1", "docId": "tmp_doc_recon", "order": 1, "tags": [],
"type": "separator"
},
{
"id": "tmp_b_code1", "docId": "tmp_doc_exploit", "order": 1, "tags": [],
"type": "code", "language": "python3", "code": "print('hello')"
}
],
"findings": [
{
"id": "tmp_f_xss",
"title": "Reflected XSS in search endpoint",
"severity": "high",
"cvssScore": 6.1,
"affectedAssets": ["app.example.com/search"],
"description": "The search parameter is reflected without sanitization.",
"poc": "<script>alert(1)</script>",
"remediation": "Encode HTML entities in the response.",
"references": ["https://owasp.org/www-community/attacks/xss/"],
"status": "confirmed",
"tags": ["xss", "web"]
}
],
"boards": [
{
"id": "tmp_brd_topology",
"name": "Topology", "kind": "topology", "locked": false,
"engagementId": "tmp_eng", "createdAt": 0, "updatedAt": 0
}
],
"boardNodes": [
{
"id": "tmp_bn_host1", "boardId": "tmp_brd_topology",
"refType": "host", "refId": "tmp_b_host1",
"x": 100, "y": 100,
"data": { "ip": "10.0.0.1", "hostname": "web.example.com", "ports": ["22/tcp", "80/tcp", "443/tcp"] }
},
{
"id": "tmp_bn_finding1", "boardId": "tmp_brd_topology",
"refType": "finding", "refId": "tmp_f_xss",
"x": 300, "y": 100,
"data": { "title": "Reflected XSS in search endpoint", "severity": "high", "cvssScore": 6.1 }
}
],
"boardEdges": [
{
"id": "tmp_be_1", "boardId": "tmp_brd_topology",
"source": "tmp_bn_host1", "target": "tmp_bn_finding1",
"label": "exploits"
}
],
"activity": [
{
"id": "tmp_act_1", "engagementId": "tmp_eng",
"timestamp": 0, "actor": "operator",
"kind": "engagement.create", "message": "Engagement created"
}
]
}