This document is for users, operators, and reviewers of the SentinelX agent
(this repo, sentinelx-cloud-core). It explains what the agent is designed
to defend against, how to report vulnerabilities, and what the project
considers in-scope vs. out-of-scope.
For a deeper technical breakdown of the threats and trust boundaries, see
THREAT_MODEL.md.
Please do NOT open public GitHub issues for security bugs.
Use GitHub's Private Vulnerability Reporting for this repository:
- Go to https://github.com/pensados/sentinelx-cloud-core/security
- Click "Report a vulnerability"
- Fill in the form (title, description, affected version, severity)
This creates a private discussion between you and the maintainer, with no public exposure until a fix is ready and the advisory is published.
If for any reason you cannot use GitHub Advisories, email
carlos@pensa.com.ar with [security] in the subject.
A useful report typically contains:
- A short description of the issue and the impact
- Steps to reproduce (commands, payloads, agent version)
- Affected files / functions if you've already located them
- Suggested fix or mitigation if you have one (optional)
- Acknowledgement: within 72 hours
- Initial assessment (triage, severity, scope): within 7 days
- Fix or mitigation: target 30 days for high/critical, best-effort otherwise
- Public disclosure: coordinated with the reporter; typically when a
fix has shipped to the public installer (
get.sentinelx.app)
If you act in good faith — meaning you don't exfiltrate data beyond what's needed to demonstrate the issue, you don't access other users' data, and you report privately before public disclosure — the project will not pursue legal action over your research.
The agent runs as sentinelx on a user's host, with passwordless sudo for
specific operations (sudo for pensa-safe-edit and listed services). It
connects out to a hub via WebSocket and exposes operations as MCP tools.
The hard rules:
-
The agent only executes what's in the operator's allowlist.
allowed_commandsin/etc/sentinelx/config.yamlis the actual security boundary. The unix user, the sudo policy, and the JWT identity all matter, but the allowlist is the line that stays enforced even if any of those is bypassed. A malicious or compromised hub cannot make the agent run an arbitrary command — only one whose prefix is already in the allowlist. -
The agent has no inbound listening ports. Only one outbound WebSocket to the hub. There is no way to reach the agent from the public internet, the LAN, or the host itself except through that single connection.
-
One compromised host does not compromise others. Each host has its own JWT identity, signed by the hub at enrollment. There is no shared secret. The hub authorizes operations per-user, not per-host-class.
-
upload_filewith a URL respects an explicit allowlist.security.trusted_fetch_hostsgates the hostname; the resolved IP is then validated against loopback / RFC1918 / link-local ranges. Redirects are disabled. https only. The default allowlist is empty (file_urleffectively disabled until the operator opts in). SeeTHREAT_MODEL.mdfor the attacker's view. -
File operations are confined to safe paths. All
target_patharguments to upload and edit operations are resolved underupload_baseviasafe_path_under()(insrc/sentinelx_core/executor_engine.py). Path traversal attempts (.., absolute paths escaping the base) are rejected before any I/O. -
No telemetry. The agent emits nothing about the host or its activity to anyone but the hub it's explicitly enrolled to. No analytics, no third-party SDKs, no calls home.
Reviewers can audit each defense at the linked path:
| Defense | Code |
|---|---|
| Command allowlist (prefix match) | src/sentinelx_core/executor.py |
| Path-traversal rejection | src/sentinelx_core/executor_engine.py (safe_path_under) |
file_url SSRF defense |
src/sentinelx_core/handlers/upload.py (_validate_fetch_url, _is_safe_ip, _NoRedirectHandler) |
file_url allowlist + timeout config |
src/sentinelx_core/policy.py (trusted_fetch_hosts, file_url_timeout_seconds) |
| Service action allowlist | src/sentinelx_core/policy.py (ServiceSpec.actions) |
| Hub JWT validation | src/sentinelx_core/identity.py |
| WebSocket reconnection (no inbound) | src/sentinelx_core/ws_client.py |
| Tests covering the above | tests/test_handlers_upload.py, tests/test_policy.py |
These are deliberate design choices, not vulnerabilities. We document them so reviewers can decide whether they're acceptable for their threat model.
-
A malicious operator. If the operator allowlists
sudo rm -rf /inconfig.yaml, the agent will happily runsudo rm -rf /. The allowlist is a tool the operator uses to constrain the LLM; it's not a safety net against the operator misusing it. -
A compromised host kernel or sudo binary. The agent runs in a standard Linux user-space environment. If
/usr/bin/sudois replaced by something malicious, or the kernel is rootkit-ed, the agent's boundaries don't help. -
Exfiltration via legitimate operations. If the operator allows
catand the LLM is convinced to runcat /etc/passwd, the contents flow back through the hub to the LLM. The defense against this is the allowlist (don't allow tools that read sensitive paths), not anything in the agent's code. -
Resource exhaustion (DoS). A malicious hub can cause many tool invocations and tie up agent resources. Rate limiting on the hub side is the appropriate mitigation; the agent itself does not currently rate-limit.
-
Side channels. Timing, error-message length, and similar oracles are not actively mitigated. We minimize obvious leaks (e.g., we don't return raw stack traces to the hub) but we don't claim constant-time behavior.
-
There is no sandbox. The agent shells out to real binaries via
subprocess.run. There is no chroot, no namespace isolation, no seccomp filter beyond what the OS givessentinelxby default. The allowlist is the boundary; if it allowlistsbash, you've just allowlisted everything. -
sudo NOPASSWDis opt-in but on by default. The installer's default grantssentinelxpasswordlesssudofor a small set of binaries (pensa-safe-edit, listed services). To install with no sudo at all, setSENTINELX_SKIP_SUDO=1during install — the agent still works, but operations that require root will fail. -
The hub is trusted with respect to message contents. The agent verifies the hub's TLS certificate and signs/verifies messages at the protocol layer, but it executes whatever (allowlisted) command the hub asks it to. If the hub is compromised, the attacker can invoke any allowlisted operation. The 4 defenses above (allowlist, no inbound, JWT identity, SSRF allowlist) cap the blast radius but don't reduce it to zero.
- Security fixes are released as patch-level versions on the
mainbranch and tagged (e.g.,v0.2.1). - Hosts running the standard installer can update with:
cd /opt/sentinelx-cloud-core && git pull && \ sudo systemctl restart sentinelx-cloud-core
- Security advisories are published at https://github.com/pensados/sentinelx-cloud-core/security/advisories.
- High-severity issues are also announced via the SentinelX hub admin channel; affected operators receive a notice in their dashboard.
Reporters who help improve the project's security are credited here (with their permission) once a published advisory closes the issue.
(no public reports yet — the project is young; this section will grow)