Every OpenShell sandbox produces a log that records network connections, process lifecycle events, filesystem policy decisions, and configuration changes. The log uses two formats depending on the type of event.
Internal operational events use Rust’s tracing framework with a conventional format:
These events cover startup plumbing, gRPC communication, and internal state transitions that are useful for debugging but do not represent security-relevant decisions.
Network, process, filesystem, and configuration events use the Open Cybersecurity Schema Framework (OCSF) format. OCSF is an open standard for normalizing security telemetry across tools and platforms. OpenShell maps sandbox events to OCSF v1.7.0 event classes.
In the log file, OCSF events appear in a shorthand format with an OCSF level label, designed for quick human and agent scanning:
The OCSF label at column 25 distinguishes structured events from standard INFO tracing at the same position. Both formats appear in the same file.
When viewed through the CLI or TUI, which receive logs through gRPC, the same distinction applies:
OpenShell maps sandbox events to these OCSF classes:
The shorthand format follows this pattern:
Class and activity (NET:OPEN, HTTP:GET, PROC:LAUNCH) identify the OCSF event class and what happened. The class name always starts at the same column position for vertical scanning.
Severity indicates the OCSF severity of the event:
Action (ALLOWED, DENIED, BLOCKED) is the security control disposition. Not all events have an action; informational config events, for example, do not.
Details vary by event class:
process(pid) -> host:port with the process identity and destinationMETHOD url with the HTTP method and targetname(pid) with exit code or command lineContext in brackets at the end provides the policy rule and enforcement engine that produced the decision.
An allowed HTTPS connection:
An L7 read-only policy denying a POST:
A connection denied because no policy matched:
A connection denied because the destination resolves to an always-blocked address:
An HTTP request to a non-default port. HTTP log URLs include the port whenever it differs from the scheme default (80 for http, 443 for https):
Proxy and SSH servers ready:
An SSH connection accepted (one event per invocation, arriving over the supervisor’s Unix socket, so there is no network peer address to log):
A process launched inside the sandbox:
A policy reload after a settings change:
Denied NET: and HTTP: events carry a [reason:...] suffix that surfaces the decision detail from the event’s status_detail field. The reason helps distinguish between policy misses, SSRF hardening, and L7 enforcement without inspecting the full OCSF JSONL record.
Common reason phrases emitted by the sandbox include:
Invalid allowed_ips entries and entries that overlap always-blocked ranges are rejected at policy-load time, so they never reach the runtime denial path. The phrases above come from the proxy’s per-CONNECT allowed_ips and SSRF checks, not from policy validation.
When the HTTP CONNECT proxy denies a request or cannot reach the upstream, it returns an HTTP error response with a JSON body. Clients can parse the body to surface actionable failure details instead of treating the status code alone.
A denied CONNECT returns 403 Forbidden:
An upstream that the proxy cannot reach returns 502 Bad Gateway:
The error field is a short machine-readable code (policy_denied, ssrf_denied, upstream_unreachable). The detail field is a human-readable explanation suitable for display in an agent transcript.
Landlock filesystem restrictions emit CONFIG: events at startup and whenever the sandbox has to skip a requested path.
On startup, the probe reports the kernel’s supported Landlock ABI version alongside the requested path counts:
When landlock.compatibility is best_effort and a requested path fails to open for reasons other than NotFound (for example, permission denied or a symlink loop), the sandbox continues without that path and emits a [MED] event so the degradation is not silent:
Set landlock.compatibility to hard_requirement in the policy to make these failures fatal instead of degraded.
Inside the sandbox, logs are written to /var/log/:
Both files rotate daily and retain the 3 most recent files to bound disk usage.