Retry and serialize pineapd/hak5 calls, queue virtual-pager keys, and grey out buttons until the pager finishes. Deploy now installs python3-light after factory firmware. Bump version to 1.3.2.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Env check is read-only when state is sane: no pineapd command-socket
writes, no live pool-list commits, no wifi reload; pineapd restarts only
when a runtime-sensitive UCI value changed or the daemon was down
- Failed monitor repairs now fail the startup contract instead of being
reported as fixed; runtime pool state is read from active config
- Enterprise AP recovery runs only on device boot (PAGER_WEBUI_BOOT), not
on every web-service restart
- serve() gates the HTTP port on startup checks with bounded retries and
shuts down cleanly on SIGTERM/SIGINT; the recon watchdog waits
interruptibly
- Recon uses a bounded userspace channel scheduler that drives both
monitor radios over non-DFS channels, with preflight verification,
serialized starts, and per-cycle error reporting
- payload.sh waits for real readiness on start, fully removes the boot
service (stop + disable + delete) on stop, and surfaces a
stopped-but-enabled boot service; deploy.sh refreshes the installed
init script even when the service is stopped
- Bump version to 1.3.1
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- STA uplink disable now uses uci commit + ip link set wlan0 down instead of
wifi reload, so the env check never bounces radios/APs/drops monitors
- Removed the wlan0mon 'hop is off' warning: field-verified hop=0 is normal
(wlan1mon also reports 0 while scanning both bands); the STA/AP pinning
checks are the real signals
- recon/status drops wlan0_hopping; UI keeps wlan0_sta + wlan0_pinned pills
The stock STA client interface (wlan0) holds phy0's channel, pinning wlan0mon
so 2.4GHz recon captures nothing (verified: iw set channel -> Resource busy
until wlan0 is down). env_check now disables it (uci wireless.dummy_radio0
disabled=1 + wifi reload) at startup and /api/recon/status exposes wlan0_sta
so the recon page can warn if it regresses.
The band UCI config looked correct but pineapd was not hopping wlan0mon at
runtime, so 2.4GHz recon results were entirely absent. env_check now parses
_pineap INTERFACE LIST and warns when wlan0mon hop is off; /api/recon/status
exposes wlan0_hopping and the recon scan bar surfaces it.
- env_check(): verifies daemon/pineapd/UCI/monitors/recon DB, auto-fixes
fixable issues and re-verifies; forces runtime SSID-pool broadcast off to
match the UI (kills the 'pool on but UI shows off' gap)
- server.py --env-check CLI; payload.sh runs it verbosely before starting,
aborts on core failure
- serve() runs the check at every startup (boot + procd respawn)
- /api/health exposes env report + pool_runtime; /api/recon/status exposes
wlan0_pinned (2.4GHz under-sampling warning); recon page warns when a
radio0 AP pins wlan0mon
- recon start failures now include the daemon reason in the UI error
- shared stabilization refactor (_stabilize_uci/PINEAPD_SAFE_UCI/_raise_monitors)
- tests: test_env_check.py (18) + health/recon updates
hak5cmd on this firmware has no CLIENT_KICK command and PINEAPPLE_DEAUTH_CLIENT
requires (bssid, target, channel) — the UI kick/deauth buttons and the MCP
pineap.kick_client tool previously passed only the client MAC, which printed
usage and silently did nothing.
- _deauth_target/_deauth_client_via_iface resolve the client's association
interface via iwinfo (Access Point + Channel), pick the band-aware inject
interface, and issue DEAUTH_CLIENT <bssid> <mac> <channel>
- h_client_kick: deny-filter (persistent) + immediate deauth with rc checks
- h_deauth_client: deauth with the full form; 502 with detail when the
client is not associated
- MCP pineap.kick_client: resolves the client first (no side effects on
failure), then deny-filter + deauth; verified on device (clean error for
unassociated clients, filter list restored)
- tests updated for the new command chain
- Rail: Attacks tab removed; PineAP becomes a grouped menu (Evil WPA /
Evil Open / Evil Enterprise / Impersonation / Clients / Filtering);
old #/attacks* hashes redirect to their PineAP equivalents.
- PineAP tabs gain Evil Enterprise; stock Open AP / Evil WPA / Enterprise
pages replaced by the verified one-click launchers (status, capture,
export, deauth, playbooks).
- Channel selects gain an Auto option: deploy resolves the target SSID's
last-seen channel from recon.db (verified unit-tested end to end).
- Harness: pi.dev prompt section removed; Copy Token inline; robot icon.
- Recon: compare checkboxes no longer hide the AP list (multi-select
stays visible, rows highlighted, clients table no longer suppressed);
Previous Scans buttons moved above the dropdown with a Delete All;
encryption chips + buckets now distinguish WPA2/WPA3 PSK vs Enterprise
(AKM suites decoded from recon bitfield bits 32-47); scan JSON carries
GPS when a fix exists; Reports tab shows a GPS column.
- fix: restore top-level EVIL_ENC definition lost in the repo (deployed
build had it; repo would have thrown at init).
wifi reloads during attack deploy/stop drop the monitor interfaces and
pineapd only recovers its primary; the monitor now brings both up
whenever it finds them down, with or without a pineapd failure.
Active PINGs on pineapd's command socket collided with the stock daemon's
own socket writes ('[PineAp] Error writing'), making the daemon watchdog
SIGTERM pineapd every ~30s while hopping. Monitor now checks pidof only
(no socket writes) and the stabilization pass pins wlan1mon hop=0.
Field-verified crash stack on this firmware: SSID-pool broadcast (segfault),
wlan2mon hopping a nonexistent 6GHz iface (segfault), wlan1mon fast-hopping
6GHz channels (ASIO thread exit), and a large refilled pool. The fix path
now enforces: pool broadcast off, pool list cleared, wlan2mon off, wlan1mon
5GHz-only, wlan0mon 2.4GHz-only — idempotent, so collect refills self-heal.
8-minute continuous-PONG stability verified on-device.
operstate reports 'unknown' on monitors (normal), so _iface_up now parses
admin flags from ip link. Discovered a second pineapd SIGSEGV source: the
wlan2mon 6GHz monitor this hardware never creates, hopping on the missing
iface (~85s crash cadence even with the SSID pool off). The monitor now
disables it in the fix path.
Mode 'active' and the advertise toggle could re-enable the SSID-pool
broadcast that segfaults pineapd. active preset now skips ssidpool/enable
(advertise stays false), the advertise endpoint refuses with an
explanation when the pool is disabled, get_ap reports the real pool
state, and the PineAP overview disables the toggle with a notice. Added
a top-bar health chip (PINEAP OK / POOL OFF / PINEAPD DOWN) polled every
15s.
Streamable-HTTP MCP server on POST /mcp: device.state, attack.deploy/stop/
status/deauth/capture/export_hc22000, loot.handshakes/enterprise_creds,
recon.aps/isearch/devices, pineap.kick_client/set_filter tools; recon DB +
bundled opencode skills resources; attack playbook prompts. Cookie or Bearer
auth. Harness page shows endpoint, token, curl snippet, capability explorer
and a copy-paste pi.dev prompt. scripts/harness_stdio.py for stdio-only
agents.
The stock daemon's enterprise config generation is broken on this firmware
(it hardcodes eap_server_erp=1, which hostapd rejects), so the enterprise
attack now runs its own karma+PineAPE hostapd instance on wlan1ent/phy1:
iw-created iface, EAP config with catch-all user file, pineape+auth capture
enabled via ctrl, mgmtiface registered in pineapd UCI so captured creds
flow into recon.db (hostap_basic/hostap_chalresp). Boot-recovery redeploys
a live attack after a Mark VIII restart.