Linux privilege graph engine — model effective access, trace escalation paths.
Project description
privmap
Linux privilege graph engine. privmap models effective access on a Linux system as a directed graph and traces concrete privilege escalation paths through it.
[CRITICAL] 2 escalation paths found for user: www-data
Path 1 — www-data → root (4 hops)
www-data
MEMBER_OF group: adm
CAN_WRITE file: /etc/logrotate.d/nginx (mode: 0664)
EXECUTES cron: /etc/cron.daily (runs-as: root)
→ root
Risk: Writable logrotate config executed by root daily cron
Remediation: chmod 644 /etc/logrotate.d/nginx; chown root:root /etc/logrotate.d/nginx
Why
Tools like LinPEAS, LinEnum, and BeRoot enumerate privilege-relevant findings as flat lists of independent observations. They report that a file is world-writable, and separately that the same file is executed by a root cron job, but they do not connect those facts into a single exploitable path. The analyst correlates the findings manually.
privmap treats this as a graph reachability problem. Every finding is a node or edge in a directed property graph. The question is not "what misconfigurations exist" but "given this user, what is reachable from here, and through what sequence of relationships."
Installation
pip install privmap
Or from source:
git clone https://github.com/isaacc2/privmap.git
cd privmap
pip install -e .
Requires Python 3.8 or later.
Usage
Live analysis
sudo privmap # full scan, all users
sudo privmap --user www-data --user bob # specific users
sudo privmap --min-severity high # filter by severity
sudo privmap --output json > report.json # JSON for SIEM
sudo privmap --output markdown > report.md
Run as root for complete results. Without root, privmap cannot read /etc/shadow, walk all of /etc, or enumerate other users' processes, and findings will be incomplete.
Snapshot mode
For offline or forensic analysis, run the collector on the target:
sudo ./collect.sh
This produces privmap_snapshot_<hostname>_<date>.tar.gz. Transfer the archive to your analysis workstation and run:
privmap --snapshot ./privmap_snapshot_target_20250101.tar.gz
The collector is POSIX-compliant and has no runtime dependencies.
CI/CD integration
privmap --exit-code --min-severity critical
Returns non-zero if any path at or above the specified severity is found.
Other options
--scan-paths /etc,/usr,/opt # custom filesystem scan paths
--max-depth 8 # max traversal depth (default 10)
--export-graph graph.json # dump full graph as JSON
-v / -vv # verbose / debug logging
How it works
- Ingestion. Reads system configuration: users, groups, sudo rules, file permissions, cron jobs, systemd units, capabilities, running processes.
- Graph construction. Each finding becomes a node or edge in a directed property graph.
- Reachability analysis. DFS traversal from each non-privileged principal toward high-value sinks (root, sudo ALL, dangerous capabilities).
- Semantic filtering. Eliminates structurally invalid paths, for example a writable file that no privileged process executes.
- Scoring. Each path is scored on exploitability and impact, then assigned a severity rating.
- Output. CLI, JSON, or Markdown with per-path remediation.
Architecture
privmap/
├── ingestion/
│ ├── identity.py # passwd, shadow, group, sudo
│ ├── filesystem.py # permission walk, SUID, ACL
│ ├── processes.py # /proc, running services
│ ├── execution.py # cron, systemd, init.d
│ └── capabilities.py # linux capabilities, namespaces
├── graph/
│ ├── model.py # node and edge types
│ ├── builder.py # ingestion coordinator
│ └── traversal.py # DFS reachability
├── analysis/
│ ├── paths.py # extraction and deduplication
│ ├── scoring.py # exploitability and impact
│ └── remediation.py # per-path fix suggestions
├── output/
│ ├── cli_output.py # rich terminal renderer
│ ├── json_export.py
│ └── markdown_export.py
└── cli.py # entry point
Scope
privmap analyses local Linux privilege relationships. It does not perform network enumeration, run exploits, cover Windows or macOS, or replace a CVE-based vulnerability scanner. It is a structural analysis tool.
Known limitations
- Argument-restricted sudo rules receive a reduced exploitability score but are not fully validated. Rules like
sudo /usr/bin/systemctl restart nginxmay still surface as findings. - Capability binaries from third-party packages are not on the known-safe allowlist and may produce false positives. The allowlist covers standard system binaries (snap-confine, ping, mtr, chronyd, and similar).
- Snapshot mode falls back to conservative behavior for filesystem permission checks on capability binaries. Live mode is more accurate.
- Cron command parsing uses regex matching on absolute paths, which can match path-like strings inside arguments or comments.
- No CVE matching. privmap does not check binary versions against known vulnerabilities. Use a vulnerability scanner alongside it.
Use cases
- System hardening. Validate least-privilege configurations and catch unintended escalation paths after changes.
- Penetration testing. Replace manual enumeration with deterministic path mapping.
- Incident response. Reconstruct how an attacker may have escalated privileges on a compromised host.
- Education and CTF. Visualise permission chains that are difficult to reason about manually.
Development
pip install -e ".[dev]"
pytest tests/ -v
ruff check privmap/
Contributing
Issues and pull requests are welcome. Run the test suite before submitting a PR. For security vulnerabilities, see SECURITY.md.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file privmap-1.0.4.tar.gz.
File metadata
- Download URL: privmap-1.0.4.tar.gz
- Upload date:
- Size: 38.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
855f5357fbcf295f17ecc77c07302c912cd05a0d50f1c5d0bbdcd5d28ed762bf
|
|
| MD5 |
e664994eb9bd2c5ec893ada86b414c47
|
|
| BLAKE2b-256 |
7c7aca8cdad5f32c6f99e298903a7b1287af8819469eef5b6a25aea38c19d1a4
|
File details
Details for the file privmap-1.0.4-py3-none-any.whl.
File metadata
- Download URL: privmap-1.0.4-py3-none-any.whl
- Upload date:
- Size: 42.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
664d85b096d389f5da726b30420454882f08add6c54b04f810a81b1f6ff078ff
|
|
| MD5 |
81ab116212f6396b3b1964b8214d18a8
|
|
| BLAKE2b-256 |
5c4bf7c6a7477da744366377c7081fd34226269e4eb1a850f9abf306df8209fa
|