PwnBroker — Complete User Guide
Install, configure and run PwnBroker — scanning, proven-exploitable vulnerability management, threat intelligence and GRC on your own infrastructure.
PwnBroker is a self-hosted security operations platform that combines network scanning, vulnerability management, dependency auditing, threat intelligence, GRC compliance, and endpoint monitoring into a single web UI. All data stays on your infrastructure.
1. Installation#
Requirements#
- Ubuntu 22.04 LTS or 24.04 LTS (Debian-based distros also work)
- 2 GB RAM minimum, 4 GB recommended
- 10 GB disk space
- Root / sudo access
- Outbound internet access (for threat intel API calls and NVD CVE lookups)
Single-File Installer (recommended)#
PWNBroker ships as one file, pwnbroker-<version>-install.run, that contains
the signed release and everything that installs it. Download it with your
license key and install in one go:
curl -fsS --data-binary @license.key https://pwnbroker.space:7585/updates/v1/installer -o pwnbroker-install.run
sudo bash pwnbroker-install.run --license license.key
Before installing it verifies its own checksum (a truncated or corrupted download is refused) and the PWNBroker release signature (a modified file is refused). Options:
| Option | Default | |
|---|---|---|
--license FILE |
— | Install this license (otherwise upload it under user menu → License) |
--port N |
443 | HTTPS port |
--dir PATH |
/opt/PWNBroker |
Install directory |
--update-url URL |
https://pwnbroker.space:7585/updates |
Update server |
--check |
Only verify the file | |
--extract DIR |
Only verify and unpack the release |
It needs Ubuntu 22.04+/Debian 12+ with systemd, x86_64 or arm64, 3 GB free
disk, and internet access for OS and Python packages. Progress is shown and
logged to /var/log/pwnbroker-install.log. Running a newer installer on an
existing server upgrades it in place and keeps all data; running the same one
again repairs the install.
Quick Install (from source)#
setup.sh manages its own git checkout — grab just the script and run it, no separate clone needed:
curl -fsSL https://raw.githubusercontent.com/ChimneyFish/PWNBroker/main/setup.sh -o setup.sh
sudo bash setup.sh
The script will:
- Install system packages:
python3,nmap,openssl,ufw, and build tools - Create a
pwnbrokersystem user (no shell, no home directory) - Clone (or, on re-runs, fetch + reset) the application into
/opt/PWNBroker - Build a Python virtual environment and install all dependencies
- Grant
nmapraw-socket capabilities (cap_net_raw) so OS fingerprinting works without root - Generate a self-signed TLS certificate (4096-bit RSA, 10-year validity)
- Create
/opt/PWNBroker/.envwith a randomly generatedSECRET_KEY - Install and enable a
systemdservice (pwnbroker.service) that starts automatically on boot - Configure
logrotatefor daily log rotation with 14-day retention - Open the HTTPS port in
ufwif the firewall is active
After the script completes you will see:
Access URL: https://<server-ip>
Default login: admin / admin
Custom Port or Install Directory#
sudo PORT=8443 INSTALL_DIR=/srv/pwnbroker bash setup.sh
Service Management#
sudo systemctl start pwnbroker # start
sudo systemctl stop pwnbroker # stop
sudo systemctl restart pwnbroker # full restart
sudo systemctl reload pwnbroker # graceful zero-downtime worker reload
sudo systemctl status pwnbroker # health check
journalctl -u pwnbroker -f # live log stream
journalctl -u pwnbroker -n 100 # last 100 log lines
Application logs are also written to /opt/PWNBroker/logs/.
TLS Certificate#
The installer generates a self-signed certificate. Your browser will show a security warning — click Advanced → Proceed to continue.
For production, upload a CA-signed certificate through Settings → HTTPS / TLS. Both the certificate (PEM) and private key (PEM) files are required. The service must be restarted after uploading.
2. First Login & Initial Setup#
- Navigate to
https://<your-server-ip> - Log in with
admin/admin - Go to Profile (bottom of the sidebar) and change your password immediately
- Go to Settings → Time & NTP and set your timezone — all timestamps across the platform will display in this zone
- Add your API keys under Settings → Threat Intelligence APIs to unlock IOC lookups, OTX feeds, and SOC triage
Recommended First Steps#
| Step | Where |
|---|---|
| Change admin password | Sidebar → Profile |
| Set timezone | Settings → Time & NTP |
| Add threat intel API keys | Settings → Threat Intelligence APIs |
| Add your first target | Targets → New Target |
| Run your first scan | Scans → New Scan |
3. Dashboard#
The dashboard is fully customizable. All widgets pull live data from the API and refresh every 30 seconds.
Customizing the Layout#
Click Customize in the top-right corner to open the widget picker panel. From there you can:
- Add any widget by clicking the
+button next to it - Remove any widget by clicking the
−button (or hover over a widget and click the×in the top-right corner) - Reorder widgets by dragging them to a new position (grab the
⠿handle that appears on hover) - Reset to the default layout with the "Reset defaults" button
Your layout is saved in the browser's localStorage and persists across page refreshes.
Available Widgets#
Stat cards (small, shows a single number with a link):
| Widget | Shows | Links to |
|---|---|---|
| Total Scans | All scans ever run | Scans |
| Running Now | Active scans | Scans |
| Targets | Configured scan targets | Targets |
| Critical Vulns | Unresolved critical findings | Vuln Management |
| High Vulns | High severity findings | Vuln Management |
| Online Agents | Endpoint agents with recent heartbeat | Threat Intel → Agents |
| Assets | Total discovered assets | Assets |
| Open SOC Cases | Pending SOC triage cases | Threat Intel → SOC Triage |
Charts (medium width):
| Widget | Chart type | Shows |
|---|---|---|
| Severity Breakdown | Doughnut | Distribution of all findings by severity |
| Scan Trend (14d) | Line | Number of scans launched per day |
| Vulns by Target | Horizontal bar | Top 5 targets ranked by vulnerability count |
| Agent Health | Status list | Online / Offline / Unknown agent counts |
Tables & Tools (full or half width):
| Widget | Shows |
|---|---|
| Recent Scans | Last 8 scans with status, vuln count, and date |
| Recent Findings | Last 10 vulnerabilities with severity, CVSS, and CVE |
| Quick Actions | One-click shortcuts to New Scan, SOC Triage, Add Target, IOC Lookup |
4. Targets#
Targets are the hosts, IP addresses, IP ranges, or domains that PwnBroker scans and monitors.
Target Types#
| Type | Example | Notes |
|---|---|---|
| Host | 192.168.1.100 |
Single IP or hostname |
| IP Range | 192.168.1.0/24 |
CIDR range, scanned as one job |
| Domain | example.com |
Enables DNS/subdomain enumeration |
Adding a Target#
- Go to Targets → New Target
- Enter a name, the host/IP/domain, and an optional description
- Click Create Target
Target Detail Page#
Clicking a target shows:
- Scan history for that target
- Domain records (for domain targets) — A, AAAA, CNAME, MX, NS records discovered via crt.sh and DNSDumpster
- DNS enumeration — click Re-Enumerate to refresh DNS records
- Subdomain changes are tracked: new records show as
new, changed values aschanged, removed entries asremoved
SSH Credentials (credentialed checks)#
Add an SSH login to a host or subnet target when you create it, or any time later with the key icon on the Targets page (filled key = a login is saved). Supported auth types:
- Password — username + password
- Key — paste an OpenSSH or PEM private key (Ed25519, ECDSA or RSA), with its passphrase if it's encrypted
Use Test login before saving: it logs in and shows the OS, the package manager it found, and whether passwordless sudo is available. Secrets are stored encrypted and never shown again; leave a secret blank when editing to keep the saved one. Remove saved credentials deletes the login.
The login is used for credentialed CVE checks (see Credentialed checks in section 7), precise end-of-life checks on full scans, and remote dependency scans. Use a dedicated low-privilege account; everything run on the host is read-only. On a subnet target the login is tried on every host found; a target saved for an individual IP takes precedence for that IP.
Deleting a Target#
Deleting a target also deletes all associated scans, results, assets, and reports. This action cannot be undone.
5. Assets#
Assets are individual network devices discovered during scans. They are tracked automatically — every completed scan populates the asset inventory.
Asset Inventory (/assets)#
The inventory table shows every known device with its:
- IP address and hostname (editable inline)
- Operating system
- Last seen timestamp
- Status (Active / Inactive)
- Tags
- Open vulnerability count
- Parent target
Tags#
Tags let you group and filter assets. Examples: production, dmz, windows, critical.
- Create a tag with a name and hex color
- Assign tags to assets from the inventory or asset row
- Filter the inventory by tag using the tag buttons at the top
Asset Groups#
Groups are collections of assets that can be scanned together as a single job. Three group types:
| Type | How assets are collected |
|---|---|
| Manual | You add assets individually |
| By Tag | All assets with a chosen tag |
| By Network | All assets belonging to a target |
Creating a group: Assets → Asset Groups → New Group
Scanning a group: On the group detail page, click Scan Group to launch a full scan against all member assets simultaneously.
Quick Scan#
From the asset inventory, click Quick Scan on any row to immediately launch a full scan of that single asset without going through the scan wizard.
6. Scans#
Scans run nmap against targets or asset groups and enrich results with CVE data from NVD.
Scan Types#
| Type | What it does |
|---|---|
| Full | Port scan + service detection + OS fingerprinting + CVE lookup |
| Port | Port scan and service detection only |
| Web | HTTP/HTTPS service checks |
| CVE | CVE lookup against already-discovered services (no new port scan) |
| OSV | Dependency vulnerability scan via SSH (see Dependency Scanner) |
Running a Scan#
- Go to Scans → New Scan
- Select a target or asset group
- Choose scan type and port range (default: 1–1024)
- Give it a name and click Launch Scan
The scan runs in the background. The scan detail page polls every 2.5 seconds and updates automatically when complete.
Scan Results#
Each scan result falls into one of these categories:
- Port — open port with service, version, and protocol
- Vulnerability — CVE-matched finding with severity, CVSS score, and remediation
- Web Check — HTTP header findings (missing security headers, etc.)
- Info — general host/OS information
Findings are color-coded by severity: Critical (red) · High (orange) · Medium (yellow) · Low (blue) · Info (gray)
Marking Findings as Remediated#
On the scan detail page, click Remediate next to any finding to mark it resolved. Remediated findings are excluded from future vulnerability ticket counts.
Scheduled Scans#
Set up recurring scans using cron expressions:
- Go to Scans → Schedule New
- Pick a target or asset group, scan type, and port range
- Choose how credentialed checks log in (same options as a one-off scan)
- Enter a cron expression (e.g.,
0 2 * * *for 2 AM daily) - Click Create Schedule
Active schedules can be paused/resumed with the toggle on the Scans index page. Scheduled scans appear in the activity log when they run.
7. Vulnerability Management#
The Vuln Management module tracks findings as tickets through their remediation lifecycle.
Only proven vulnerabilities are counted#
A CVE matched from a service's version banner only says the product can be vulnerable; whether this host is depends on configuration. (Apache 2.4.49 is only exploitable through CVE-2021-41773 if a non-default setting allows it.) So every version-matched CVE is re-tested against the live service with a check written for that CVE, and gets one of three verdicts:
| Verdict | What happened | Counted? |
|---|---|---|
| Exploitable | The check reproduced the issue. The proof (request + response) is on the finding. | Yes — open ticket with SLA |
| Not exploitable | The check ran cleanly and the vulnerable behaviour wasn't there (feature disabled, fix backported, not that product). | No — kept under "Not Exploitable" |
| Unverified | No safe check exists for this CVE, or the check couldn't complete. Each one says why. | No — kept under "Unverified" |
- Checks come from the nuclei template library (~4,500 CVEs), installed by
setup.shand refreshed weekly. nmap's own vuln-script verdicts count too (VULNERABLE proves, NOT VULNERABLE rules out; LIKELY VULNERABLE is not proof). - Only safe checks run: never ones tagged DoS/intrusive/fuzzing, never ones needing credentials, and never ones that call out to an external server — no scan data leaves your network.
- A later scan that proves an unverified finding reopens it automatically; a rescan that shows an open one is no longer exploitable (fixed, or the feature turned off) closes it as Not Exploitable.
- Verify now on the Vulnerabilities page re-tests every unverified finding without a full rescan (useful after the check library updates).
- Dashboard, reports, exports and Jira/Confluence only include proven vulnerabilities. Dependency (OSV), EOL, secrets and other non-version findings are unchanged.
- Set
VULN_VERIFY=0in.envto turn checking off (findings then stay unverified).
Credentialed checks (SSH)#
Most version-matched CVEs have no safe remote check, so on their own they stay Unverified. With an SSH login, scans also look inside the host and rule out the ones that don't apply:
| Rule-out | How it's checked |
|---|---|
| Vendor backport | Finds the package that owns the listening service, its exact installed version, and the vendor changelog. If the changelog lists the CVE, the fix is installed even though the banner shows the old upstream version. Ubuntu trims the on-disk changelog, so the full one for that exact version is fetched from changelogs.ubuntu.com (only the package name and version are sent). |
| Module not loaded | For Apache httpd (apachectl -M) and nginx (nginx -V): a CVE in a module the server doesn't load is ruled out. |
| Different OS | A CVE that only affects the product on Windows, on a host running Linux/Unix. |
Credentialed checks only ever rule findings out. They never make a finding count as a vulnerability on their own; that still needs a live check that reproduces it. Findings they can't rule out stay Unverified with a note saying what was found (e.g. "apache2-bin 2.4.52-1ubuntu4.26 has no vendor fix listed for CVE-…").
On New Scan / Schedule Scan, Credentialed Checks (SSH) chooses the login:
- Use the target's saved SSH login (default): uses the login saved on the target.
- Use these credentials for this scan: enter a login just for this scan (stored encrypted with the scan). For a subnet or asset group it's tried on every host.
- Off: don't log in to hosts.
Each scan shows which login it used, and adds one info row per host with how many CVEs were ruled out, or why the login failed. Verify now reuses each finding's scan login (or its target's). In a real test against stock Ubuntu 22.04 Apache, credentialed checks ruled out 88 of 95 version-matched CVEs.
Vuln Tickets (/vulns/tickets)#
A ticket is automatically created for each unique vulnerability the first time it is found on a host. If the same CVE reappears on the same host in a later scan, the existing ticket is updated rather than duplicated.
Ticket statuses:
| Status | Meaning |
|---|---|
| Open | Newly found, not yet being worked |
| In Progress | Someone is actively remediating |
| Patched | Fix confirmed |
| Accepted Risk | Risk accepted by the team |
| False Positive | Finding is wrong (marked by hand) |
| Unverified | Version match only, not proven on this host (no SLA) |
| Not Exploitable | The CVE's check ran and the issue wasn't present (no SLA) |
SLA tracking: Each severity level has a default SLA (Critical: 1 day, High: 7 days, Medium: 30 days, Low: 90 days). Overdue tickets are highlighted in red.
Device View (/vulns/device/<target>)#
Shows all open tickets grouped by target with a risk heat-map. Use this view to get a per-host risk summary.
Updating a Ticket#
Click any ticket to open the detail panel and:
- Change status
- Assign to a user
- Add notes
- Record the patch date
8. Dependency Scanner#
The dependency scanner connects to a target over SSH, reads the installed package manifest, and cross-references it against the OSV (Open Source Vulnerabilities) database.
Supported Ecosystems#
Python (pip), Node.js (npm), Go modules, Rust (Cargo), Ruby (Bundler), Java (Maven/Gradle), PHP (Composer), and others supported by OSV.
Prerequisites#
- The target must have SSH enabled and credentials configured on the Target detail page
- Test the connection with Test SSH before running a scan
Running a Dependency Scan#
- Go to Dependency Scanner → New Scan
- Select a target that has SSH credentials configured
- Optionally specify a path on the remote host to scan (defaults to home directory)
- Click Launch
Results#
Results list each vulnerable package with:
- Package name and installed version
- First fixed version
- CVE ID and CVSS score
- Severity badge
Click Remediate on any row to mark it resolved.
9. Reports#
Reports generate PDF or HTML summaries of scan results.
Generating a Report#
- Go to Reports
- Find a completed scan in the table
- Click Generate and choose PDF or HTML format
The report includes: executive summary, severity breakdown chart, full findings table with CVSS scores and remediation advice, and scan metadata.
Downloading Reports#
Generated reports appear in the Saved Reports table. Click Download to save the file locally.
Pushing Reports to a Cloud API#
If you have configured a Cloud API endpoint under Settings → Cloud API Integration, click Push next to any saved report to POST it to the endpoint. The payload includes scan metadata and optionally a base64-encoded copy of the report file.
Scheduled Reports#
Schedule automatic report delivery by email:
- Go to Reports → Schedule New
- Select a target, cron schedule, recipients, and format
- Click Create Schedule
Recipients will receive an email with the report attached each time the schedule fires. SMTP must be configured under Settings → Email / SMTP.
Atlassian Integration#
If Confluence and/or Jira are configured under Settings → Atlassian:
- Publish to Confluence: From the scan detail page, click Publish to Confluence to create a formatted wiki page in your configured space
- Create Jira Tickets: From the scan detail page, click Create Jira Tickets to open issues for findings at or above your configured severity threshold
10. Threat Intelligence#
The Threat Intelligence module provides IOC lookups, threat feed monitoring, SOC triage workflows, subdomain enumeration, and domain-change tracking.
Required API Keys#
Configure all keys under Settings → Threat Intelligence APIs.
| Service | Used for |
|---|---|
| OTX (AlienVault) | IOC reputation, threat feed pulses |
| AbuseIPDB | IP abuse reports and confidence scores |
| GreyNoise | Internet noise classification (RIOT / mass-scanner detection) |
| DNSDumpster | Subdomain enumeration |
| NVD | CVE lookup and CVSS enrichment |
Click Test All Keys on the Settings page to validate each key without leaving the page.
IOC Lookup (/threat/lookup)#
Enter any of the following and get a multi-source reputation report:
- IPv4 / IPv6 address
- Domain name
- File hash (MD5, SHA-1, SHA-256)
- URL
Results are cached for 24 hours to avoid burning API quota.
OTX Feed (/threat/feed)#
Displays the latest threat pulses from your AlienVault OTX subscriptions. Each pulse shows indicator counts, tags, and adversary attribution. Requires an OTX API key.
SOC Triage (/threat/triage)#
The triage queue collects IOCs that need analyst review. IOCs reach the queue either:
- Manually submitted via the Lookup page when the threat score exceeds the threshold
- Automatically when an endpoint agent reports a network connection to a known-malicious IP and GreyNoise or VT confirm it
Triage actions:
| Action | Meaning |
|---|---|
| Alert | Flag as confirmed threat, add analyst notes |
| Dismiss | Mark as benign / false positive |
Alerted cases can be exported. Dismissed cases are removed from the active queue but retained in history.
Subdomain Enumeration (/threat/subdomains)#
Enter a domain to enumerate subdomains using crt.sh certificate transparency logs and DNSDumpster. Results show IP addresses, record types, and first/last seen dates.
11. Endpoint Agents#
Endpoint agents are lightweight Python scripts that run on monitored hosts. They send heartbeats and report suspicious network connections back to PwnBroker.
How Agents Work#
- The agent runs as a background process (service/daemon) on the endpoint
- Every 60 seconds it sends a heartbeat with the host's IP, OS, and hostname
- It monitors active network connections and cross-checks destination IPs against your IOC database
- If a connection to a known-malicious IP is detected, an alert is created in PwnBroker
- Agents that have not sent a heartbeat in 5 minutes are marked Offline
Deploying an Agent#
Step 1 — Download the agent script#
Go to Threat Intel → Agents → Download Agent. The download page shows three options:
| Platform | File | Method |
|---|---|---|
| Linux | install_linux.sh |
Bash one-liner |
| macOS | install_mac.sh |
Bash one-liner |
| Windows | install_windows.ps1 |
PowerShell script |
Each installer downloads the Python agent, sets the server URL and registration token automatically, and installs it as a system service.
Step 2 — Note the registration token#
The registration token is auto-generated. Find it on the Threat Intel → Agents → Download Agent page (/threat/download). All agents must present this token when registering for the first time. You do not need to set it manually — it is created automatically on first use.
Step 3 — Install on the endpoint#
Linux / macOS:
curl -k https://<pwnbroker-server>/threat/download/script/linux | sudo bash
Windows (PowerShell as Administrator):
iwr https://<pwnbroker-server>/threat/download/script/windows -UseBasicParsing | iex
Step 4 — Verify registration#
The agent appears in Threat Intel → Agents within a minute of first startup. Status shows Online when heartbeats are received.
Agent Alerts#
When an agent detects a suspicious connection, the alert appears on:
- The agent's detail page
- The Threat Intel overview page
- The SOC Triage queue (if the threat score exceeds the threshold)
Acknowledge alerts from the agent detail page to clear them from the active list.
Manual Registration (advanced)#
python3 pwnbroker_agent.py --register --no-verify-ssl
This prompts for server URL and registration token, saves the config, then exits. Subsequent runs without --register operate in normal heartbeat mode.
12. GRC — Governance, Risk & Compliance#
The GRC module manages risk registers, compliance frameworks, and security policies.
Risk Register (/grc/risks)#
Track risks across five categories: Technical, Operational, Compliance, Strategic, Financial.
Risk scoring: likelihood (1–5) × impact (1–5) = risk score (1–25)
| Score | Level |
|---|---|
| 1–5 | Low |
| 6–11 | Medium |
| 12–19 | High |
| 20–25 | Critical |
Risk statuses: Open · In Treatment · Mitigated · Accepted · Transferred · Closed
Each risk can have a mitigation plan, target date, assigned owner, and optionally be linked to a specific asset. Residual likelihood and impact can be recorded after controls are applied to show risk reduction.
Compliance (/grc/compliance)#
PwnBroker ships with seeded compliance frameworks:
- NIST CSF 2.0 — Govern, Identify, Protect, Detect, Respond, Recover
- CIS Controls v8 — 18 control groups
- ISO 27001:2022 — Annex A controls
Assessing a control: Click any framework to see its controls. Click Assess on any control to record:
- Status: Compliant · Partial · Non-Compliant · Not Applicable · Not Assessed
- Evidence notes
- Next review date
Auto-assessment: Click Run Auto-Assessment to have PwnBroker automatically evaluate controls it can infer from scan data (e.g., patch status, open ports, missing headers).
Evidence files: Upload supporting evidence documents (PDFs, screenshots, configs) directly to a control.
Compliance report: Generate a PDF compliance report for any framework showing pass/fail counts and a gap summary. Useful for auditors.
Policies (/grc/policies)#
Maintain a library of security policies with version tracking.
Policy categories: Access Control · Data Classification · Incident Response · Vulnerability Management · Change Management · Acceptable Use · General
Policy statuses: Draft · Active · Under Review · Retired
Each policy tracks the owner, approver, approval date, and next review date. Overdue review dates are highlighted in red.
13. Settings#
Time & NTP#
Timezone: Select any IANA timezone from the dropdown. All timestamps across the entire platform — scans, findings, activity logs, SOC cases — display in this timezone. The preview updates live as you change the selection.
NTP Server: Enter the hostname of your NTP server (e.g., pool.ntp.org, time.cloudflare.com). PwnBroker writes this to /etc/systemd/timesyncd.conf and restarts the sync service. This requires the process to run as root or have sudo access — if it fails, the timezone is still saved and the error message shows the exact command to run manually.
Email / SMTP#
Configure outbound email for scheduled reports and alerts.
| Field | Example |
|---|---|
| SMTP Server | smtp.gmail.com |
| Port | 587 |
| Use STARTTLS | Checked |
| Username | alerts@company.com |
| Password | App password (not your login password) |
| From Address | pwnbroker@company.com |
Use the Send Test Email button to verify the configuration before saving.
Threat Intelligence APIs#
API keys are stored in the database. Entering a key and saving replaces the existing value; leaving a field blank keeps the current key. Click Test All Keys to verify connectivity for each configured service.
Atlassian Integration#
Connect to Confluence and Jira for automated report publishing and ticket creation.
| Field | Notes |
|---|---|
| Base URL | https://yourorg.atlassian.net |
| Your Atlassian account email | |
| API Token | Generate at id.atlassian.com → Security → API tokens |
| Confluence Space Key | e.g., SEC |
| Parent Page ID | Optional — found in the page URL |
| Jira Project Key | e.g., SEC |
| Issue Type | Usually Bug or Security |
| Minimum Severity | Only findings at or above this level create Jira tickets |
Cloud API Integration#
Forward scan reports to an external API endpoint (e.g., a SIEM, ticketing system, or custom webhook).
PwnBroker POSTs a JSON payload containing scan metadata, all findings, and optionally a base64-encoded report file. Authentication options: None, Bearer Token, or API Key header.
HTTPS / TLS#
Upload a CA-signed certificate to replace the self-signed one. Provide both the certificate file (PEM/CRT/CER) and the matching private key file (PEM/KEY). The pair is validated before being written to disk. Restart the service after uploading:
sudo systemctl restart pwnbroker
14. User Management#
Users are managed under Settings → User Management (admin only).
Roles#
| Role | Permissions |
|---|---|
| Admin | Full access: create/delete targets, run scans, manage users and settings, generate reports |
| User | Read-only: view dashboard, scans, targets, and reports; update own profile |
Adding a User#
Fill in username, email, temporary password, and role, then click Add User. The user can change their password under Profile.
Managing Existing Users#
- Change role: Select from the dropdown in the role column — takes effect immediately
- Disable/Enable: Prevent login without deleting the account
- Delete: Permanently removes the account (cannot be undone)
You cannot change your own role or delete your own account.
Profile#
Each user can update their own username, email, and password under Sidebar → Profile. Admins do not need to be involved for password changes.
15. Activity Log#
The Activity Log (/activity) is an immutable audit trail of every significant action taken in PwnBroker. It is only visible to admin users.
Each entry records:
- Timestamp (in the configured timezone)
- Actor (username or "System" for automated actions)
- Action type (e.g.,
scan.created,user.login,settings.threat_save) - Entity name (e.g., the scan name or target)
- Detail string
- Source IP address
The log is grouped by date. Hover over a timestamp to see the full date/time with seconds.
Admins can clear the entire log with the Clear Log button. This is irreversible.
16. API Reference#
PwnBroker exposes a small JSON API for programmatic access. All endpoints require an authenticated session (cookie-based).
GET /api/dashboard/stats#
Returns basic dashboard counts.
{
"total_scans": 42,
"running_scans": 1,
"total_targets": 8,
"total_vulns": 137,
"critical_vulns": 5
}
GET /api/dashboard/widgets#
Returns all dashboard widget data in one call. Used by the dashboard widget system.
{
"stats": {
"total_scans": 42,
"running_scans": 1,
"total_targets": 8,
"total_assets": 64,
"online_agents": 3,
"open_soc": 2,
"critical_vulns": 5,
"high_vulns": 18,
"medium_vulns": 61,
"low_vulns": 48,
"info_vulns": 5
},
"severity_map": { "critical": 5, "high": 18, "medium": 61, "low": 48, "info": 5 },
"trend": {
"labels": ["Jun 04", "Jun 05", "..."],
"data": [2, 0, 1, 3, "..."]
},
"vuln_by_target": {
"labels": ["web-server", "db-host"],
"data": [42, 19]
},
"agent_stats": { "online": 3, "offline": 1, "unknown": 0 },
"recent_scans": [ { "id": 9, "name": "...", "status": "done", "..." } ],
"recent_vulns": [ { "severity": "critical", "title": "...", "cve_id": "CVE-2024-..." } ]
}
GET /api/scans/<scan_id>/status#
Poll the live status of a running scan. Used by the scan view page.
{
"id": 9,
"status": "running",
"vuln_count": 12,
"critical_count": 2,
"duration": null
}
status values: pending · running · done · failed
Endpoint Agent API#
These endpoints are used exclusively by the agent script.
POST /threat/api/register#
Register a new agent. Requires the pre-shared registration token.
// Request
{
"reg_token": "<registration-token>",
"hostname": "workstation-01",
"os": "linux",
"os_version": "Ubuntu 22.04",
"ip_address": "10.0.0.45"
}
// Response 200
{
"agent_id": "abc123...",
"token": "<agent-session-token>"
}
POST /threat/api/heartbeat#
Send a periodic heartbeat with current network connections. Requires the agent's session token in the X-Agent-Token header.
// Request body (auth via X-Agent-ID and X-Agent-Token headers)
{
"ip_address": "10.0.0.45",
"connections": [
{ "remote_ip": "185.220.101.5", "status": "ESTABLISHED", "pid": 1234 }
]
}
// Response 200
{ "ok": true }
17. Upgrading#
/opt/PWNBroker is a live git checkout, so upgrading is a normal git pull:
cd /opt/PWNBroker
sudo git pull
sudo systemctl restart pwnbroker
Or re-run sudo bash setup.sh — it's safe and idempotent, fetching and resetting to the latest commit, updating Python dependencies, and restarting the service, without touching data/, logs/, evidence_uploads/, your existing .env, or TLS certificates.
New database columns (added by migrations) are applied automatically on startup by _migrate_columns() in app/__init__.py. No manual schema changes are needed.
18. Troubleshooting#
Service won't start#
# Check the last 50 log lines
journalctl -u pwnbroker -n 50
# Common causes:
# - Port already in use: ss -tlnp | grep 443
# - Missing .env file: ls /opt/PWNBroker/.env
# - Bad TLS cert: openssl x509 -in /opt/PWNBroker/data/ssl/cert.pem -noout -text
# - Python import error: /opt/PWNBroker/venv/bin/python -c "from app import create_app; create_app()"
Scans stuck in "running" state#
The scan background thread may have died. Restart the service:
sudo systemctl restart pwnbroker
Scans still marked running at that point were killed mid-scan, not still in progress — the app automatically sweeps any running scan to failed on every boot (_recover_orphaned_scans in app/__init__.py), so no manual database edit is needed.
OS detection not working#
nmap needs CAP_NET_RAW for -O (OS fingerprinting). Re-run the capability grant:
sudo setcap cap_net_raw+eip,cap_net_admin+eip $(which nmap)
Verify it worked:
getcap $(which nmap)
# Expected: /usr/bin/nmap cap_net_admin,cap_net_raw+eip
API keys "INVALID" even though they are correct#
- Ensure there are no leading/trailing spaces in the key fields
- Some services (NVD) have rate limits — a 429 response is treated as "key accepted"
- Network issues (DNS, firewall) to the external APIs will show as "Network error"
Timezone not applying to old timestamps#
The localdt Jinja2 filter converts UTC datetimes at render time. All timestamps stored in the database are always UTC — only the display changes. If a page is still showing UTC, hard-refresh the browser (Ctrl+Shift+R) to clear cached template responses.
Agents showing as Offline immediately#
The agent is considered Offline if no heartbeat is received within 5 minutes. Common causes:
- The agent process is not running — check the service status on the endpoint
- The server URL in the agent config is wrong or not reachable from the endpoint
- TLS verification is failing — re-run the agent with
--no-verify-sslif using a self-signed cert
Agent config file location:
- Linux/macOS: ~/.pwnbroker_agent.json
- Windows: %APPDATA%\pwnbroker_agent.json
"Permission denied" when setting NTP server#
PwnBroker writes to /etc/systemd/timesyncd.conf. If the service runs as the pwnbroker user (not root), this will fail. The timezone setting is always saved regardless. To apply the NTP server change manually:
sudo nano /etc/systemd/timesyncd.conf
# Set: NTP=your.ntp.server
sudo systemctl restart systemd-timesyncd
sudo timedatectl set-ntp true
Database locked errors#
SQLite allows only one writer at a time; the app runs it in WAL mode with a busy-timeout so concurrent reads/writes don't immediately fail, but if you still see "database is locked" errors under heavy load, consider switching to PostgreSQL:
# Install psycopg2
/opt/PWNBroker/venv/bin/pip install psycopg2-binary
# Update DATABASE_URL in /opt/PWNBroker/.env
DATABASE_URL=postgresql://pwnbroker:password@localhost/pwnbroker
# Create the database
sudo -u postgres createuser pwnbroker
sudo -u postgres createdb -O pwnbroker pwnbroker
sudo -u postgres psql -c "ALTER USER pwnbroker WITH PASSWORD 'password';"
# Restart to apply
sudo systemctl restart pwnbroker
PwnBroker — built for security teams that prefer owning their own data.