{"id":47604276,"url":"https://github.com/nikolas-trey/praesidium","last_synced_at":"2026-04-01T19:02:09.671Z","repository":{"id":345607053,"uuid":"1186755313","full_name":"nikolas-trey/Praesidium","owner":"nikolas-trey","description":"An Android physical security tool","archived":false,"fork":false,"pushed_at":"2026-03-31T00:13:48.000Z","size":2417,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-31T01:43:06.605Z","etag":null,"topics":["blue-team","cybersecurity","opsec","physical-security","security","security-tools"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nikolas-trey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-20T00:39:42.000Z","updated_at":"2026-03-31T00:13:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/nikolas-trey/Praesidium","commit_stats":null,"previous_names":["umutcamliyurt/praesidium","nikolas-trey/praesidium"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/nikolas-trey/Praesidium","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolas-trey%2FPraesidium","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolas-trey%2FPraesidium/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolas-trey%2FPraesidium/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolas-trey%2FPraesidium/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikolas-trey","download_url":"https://codeload.github.com/nikolas-trey/Praesidium/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolas-trey%2FPraesidium/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31291011,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blue-team","cybersecurity","opsec","physical-security","security","security-tools"],"created_at":"2026-04-01T19:02:02.822Z","updated_at":"2026-04-01T19:02:09.637Z","avatar_url":"https://github.com/nikolas-trey.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cbr/\u003e\n\n# An Android physical security tool\n\n\u003cbr/\u003e\n\n\u003cimg src=\"banner.png\" width=\"500\"\u003e\n\n![Platform](https://img.shields.io/badge/platform-Android-3DDC84?style=flat-square\u0026logo=android\u0026logoColor=white)\n![Language](https://img.shields.io/badge/language-Java-ED8B00?style=flat-square\u0026logo=openjdk\u0026logoColor=white)\n![API](https://img.shields.io/badge/min%20API-26-informational?style=flat-square)\n![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)\n\n\u003cbr /\u003e\n\n\u003c/div\u003e\n\n---\n\n## Overview\n\nPraesidium is an Android security tool designed to protect devices from physical and software-level intrusion. Running as a persistent foreground service, it continuously monitors for threat indicators — ADB connections, brute-force unlock attempts, and anomalous process behaviour — and responds with configurable emergency actions including screen lock, device reboot, or full factory wipe.\n\nIt is intended for security-conscious users, researchers, and administrators who require automated, policy-driven responses to device compromise scenarios.\n\n---\n\n## Table of Contents\n\n- [Features](#features)\n- [Requirements](#requirements)\n- [Installation \u0026 Setup](#installation--setup)\n- [Threat Detection](#threat-detection)\n- [Emergency Actions](#emergency-actions)\n- [Configuration Reference](#configuration-reference)\n- [Known Limitations](#known-limitations)\n- [License](#license)\n\n---\n\n## Features\n\n| Capability | Description |\n|---|---|\n| **ADB Connection Detection** | Detects active ADB sessions via `/proc/net/tcp` inspection |\n| **Brute-Force Protection** | Tracks cumulative failed unlock attempts via the Device Admin API |\n| **FD Spike Detection** | Monitors `adbd` file descriptor count for anomalous growth |\n| **Automated Response** | Per-threat configurable actions: lock, reboot, or wipe |\n| **Confirmation Counting** | Reboot requires 5 consecutive confirmations; wipe requires 10 — prevents single-poll false positives |\n| **Manual Emergency Controls** | One-tap lock, reboot, and wipe from the main UI |\n| **Admin Toggle** | Activate and deactivate Device Administrator and Device Owner status from within the app |\n| **Persistence** | Service auto-restarts after device reboot via `BOOT_COMPLETED` |\n| **Granular Settings** | Individual toggle and action assignment for each threat type |\n\n---\n\n## Requirements\n\n### Permissions\n\n| Permission | Purpose |\n|---|---|\n| `RECEIVE_BOOT_COMPLETED` | Restart service after device boot |\n| `FOREGROUND_SERVICE` | Persistent background monitoring |\n| `BIND_DEVICE_ADMIN` | Device Administrator binding |\n\n### Device Admin\n\nLock functionality requires the app to be granted **Device Administrator** privileges. The user is prompted to grant this on first launch. Privileges can be revoked at any time using the **Deactivate** button on the main screen.\n\n### Device Owner *(optional)*\n\nReboot and wipe actions require **Device Owner** status. This must be configured before use:\n\n```bash\nadb shell dpm set-device-owner com.nikolas-trey.praesidium/.DeviceAdminReceiver\n```\n\n\u003e ⚠️ Device Owner can only be set on a device with no accounts added, or via ADB before setup is complete. See [Installation \u0026 Setup](#installation--setup) for the correct sequence.\n\n---\n\n## Installation \u0026 Setup\n\n### 1. Build \u0026 Install\n\n```bash\n# Clone the repository\ngit clone https://github.com/nikolas-trey/Praesidium.git\ncd Praesidium\n\n# Build release APK\n./gradlew assembleRelease\n\n# Install to connected device\nadb install app/build/outputs/apk/release/app-release.apk\n```\n\n### 2. Grant Device Owner *(recommended — do this before adding any accounts)*\n\nTo enable reboot and wipe actions, set the app as Device Owner **before** adding any Google or other accounts to the device. The easiest time to do this is immediately after a factory reset, during initial setup:\n\n```bash\n# Skip adding a Google account in the setup wizard, then:\nadb shell dpm set-device-owner com.nikolas-trey.praesidium/.DeviceAdminReceiver\n```\n\nIf accounts are already present, remove them all via **Settings → Accounts**, then run the command above.\n\n\u003e ⚠️ Device Owner cannot be set if any accounts exist on the device. The command will throw `IllegalStateException` if this condition is not met.\n\n### 3. Grant Device Administrator\n\nOpen the app. If Device Owner was not set via ADB, a system dialog will appear requesting Device Administrator access. Grant it to enable at minimum the lock action.\n\n### 4. Configure Threat Responses\n\nOpen **Settings** within the app to:\n- Enable or disable individual threat detectors\n- Set the failed unlock threshold (minimum: 3)\n- Assign an action (lock / reboot / wipe) to each threat type\n\nThe service starts automatically on launch and persists across reboots.\n\n### 5. Deactivating\n\nTo remove all privileges, tap the **Deactivate** button on the main screen. This clears Device Owner status first, then removes Device Administrator, and stops the background service. A confirmation dialog is shown before any changes are made.\n\n---\n\n## Threat Detection\n\n### ADB Connection — `adb_connected`\n\n**Method:** Parses `/proc/net/tcp` and `/proc/net/tcp6` on every poll cycle.\n\n**Trigger:** An ESTABLISHED connection (`state = 0x01`) on either of the standard ADB ports:\n\n| Port (decimal) | Port (hex) | Protocol |\n|---|---|---|\n| 5555 | `0x15B3` | ADB over TCP |\n| 5037 | `0x13AD` | ADB host daemon |\n\n**Boot loop protection:** The ADB action is capped at **lock** regardless of the configured action. Allowing reboot or wipe for ADB detection would cause an infinite boot loop if a cable remains connected across reboots.\n\n**Default action:** Lock\n\n---\n\n### Brute-Force Unlock — `brute_force`\n\n**Method:** `DeviceAdminReceiver.onPasswordFailed()` fires for every failed unlock attempt. A cumulative counter is persisted in SharedPreferences using synchronous `commit()` writes to ensure data survives an immediately following reboot or wipe.\n\n**Trigger:** Counter reaches or exceeds the configured threshold (default: 5, minimum enforced: 3).\n\n**Boot grace period:** Brute-force detection is suppressed for **5 minutes** after boot. This prevents a counter left over from a previous session from firing an action the moment the service starts.\n\n**Reset behaviour:**\n- Automatic reset on successful unlock (`onPasswordSucceeded`) — synchronous write\n- Automatic reset before action is executed — synchronous write, ensuring the counter reaches disk before a reboot or wipe can erase it\n\n**Default action:** Lock\n\n---\n\n### ADB FD Spike — `adb_fd_spike`\n\n**Method:** At service start, the `adbd` process's open file descriptor count is sampled multiple times from `/proc/\u003cpid\u003e/fd` to establish a stable baseline. On each poll, the current count is compared to this baseline.\n\n**Trigger:** Current FD count exceeds `baseline + 15`.\n\n**Baseline requirements:** At least 3 out of 5 calibration samples must succeed. If fewer succeed, FD spike detection is disabled for the session to prevent a bad baseline from producing instant false positives.\n\n**Boot grace period:** FD spike detection is suppressed for **2 minutes** after service start. `adbd` opens and closes file descriptors during early initialisation; a low calibration baseline combined with normal post-boot activity would otherwise produce false spikes.\n\n**Default action:** Lock\n\n---\n\n## Emergency Actions\n\nAll actions are executed via `DevicePolicyManager` and guarded by capability checks. If the required privilege is not held, the action falls back to lock rather than failing silently.\n\n| Action | Capability Required | Confirmation Count | Behaviour |\n|---|---|---|---|\n| **Lock** | Device Administrator | 1 | Calls `lockNow()` — immediately locks the screen |\n| **Reboot** | Device Owner | 5 | Calls `dpm.reboot()` — performs a clean system reboot |\n| **Wipe** | Device Owner | 10 | Calls `wipeData()` with `WIPE_EXTERNAL_STORAGE` and `WIPE_RESET_PROTECTION_DATA` — full factory reset |\n\n\u003e ⚠️ **Wipe is irreversible.** All user data, installed apps, and external storage content will be permanently erased. Manual wipe from the UI requires explicit confirmation. Automated wipe executes when the threat persists for 10 consecutive poll cycles (~10 seconds).\n\n---\n\n## Configuration Reference\n\nAll preferences are stored in `SharedPreferences` under the file name `praesidium_prefs`.\n\n### Detection Toggles\n\n| Key | Type | Default | Description |\n|---|---|---|---|\n| `detect_adb` | `boolean` | `true` | Enable ADB connection detection |\n| `detect_brute_force` | `boolean` | `true` | Enable brute-force unlock detection |\n| `detect_fd_spike` | `boolean` | `true` | Enable ADB file descriptor spike detection |\n| `failed_unlock_threshold` | `int` | `5` | Failed unlocks before brute-force triggers (minimum: 3) |\n\n### Action Assignments\n\n| Key | Type | Default | Valid Values | Notes |\n|---|---|---|---|---|\n| `action_adb` | `string` | `lock` | `lock`, `reboot`, `wipe` | Reboot/wipe silently demoted to `lock` at runtime |\n| `action_brute_force` | `string` | `lock` | `lock`, `reboot`, `wipe` | |\n| `action_fd_spike` | `string` | `lock` | `lock`, `reboot`, `wipe` | |\n| `default_action` | `string` | `lock` | `lock`, `reboot`, `wipe` | Fallback for unrecognised threat keys |\n\n### Internal State\n\n| Key | Type | Description |\n|---|---|---|\n| `failed_unlock_cumulative` | `int` | Running count of failed unlock attempts since last reset |\n| `response_enabled` | `boolean` | Master switch — disables all automated responses when `false` |\n\n---\n\n## Known Limitations\n\n- **`/proc` access** — Reading `/proc/net/tcp` and `/proc/\u003cpid\u003e/fd` may be restricted on hardened or custom ROMs. Detection will silently fail (return no threat) if access is denied.\n- **Device Owner requirement** — Reboot and wipe require Device Owner status, which must be configured before the device has accounts added. This significantly limits deployment on already-provisioned devices.\n- **Counter persistence** — The brute-force counter is stored in SharedPreferences and does not survive a wipe. It does survive a reboot.\n- **ADB over USB** — The TCP-based ADB check may not reliably detect all ADB-over-USB configurations depending on kernel implementation.\n- **No tamper protection** — If an attacker force-stops the app or revokes Device Administrator status before a threat is acted upon, the response will fail silently.\n- **Polling latency** — Threat detection has up to a 1-second response delay by design.\n- **Device Owner deactivation** — Once Device Owner is cleared via the in-app Deactivate button, it cannot be re-granted without either a factory reset or re-running the `adb shell dpm set-device-owner` command on a device with no accounts.\n\n---\n\n## License\n\nDistributed under the **MIT License**. See [`LICENSE`](LICENSE) for full terms.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikolas-trey%2Fpraesidium","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikolas-trey%2Fpraesidium","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikolas-trey%2Fpraesidium/lists"}