Security review · NVIDIA OpenShell
OpenShell connect, reviewed from the code.
ArtzAIn, the model-agnostic agent control plane, checks every governed change your OpenShell gateway makes before it commits, and signs each decision into a ledger nobody can quietly edit. This page tells your security team what ArtzAIn does on your host, what leaves it and where it goes, how the credentials work, and what happens when something fails or is attacked. We wrote every answer from the shipped code.
- Release covered
- artzain 0.6.48: the sidecar, the connect command and the connect script
- Sidecar image
- sha256:2c6232a3…43efa
- OpenShell approved by default
- 0.1.2
- As of
- 2026-10-09
01 · At a glance
ArtzAIn decides and records. OpenShell enforces.
Your OpenShell gateway calls a small ArtzAIn sidecar, running beside it on your host, before it commits a governed write. The sidecar asks the hosted ArtzAIn engine for a decision. ArtzAIn evaluates your policy bundle and seals the decision as a signed, hash-chained receipt, so you can prove later what was allowed and why. The sidecar then tells your gateway to commit the write or refuse it.
| Promise | Status | As built |
|---|---|---|
| ArtzAIn never reaches into your network | Holds | The sidecar only calls out, over HTTPS, to one ArtzAIn origin. Nothing calls in. It listens on a Unix socket for your gateway and on a loopback port for its own command-line tool, both on your host. |
| ArtzAIn never sees your prompts or secrets | Holds, with limits | It sees no prompts. The sidecar drops every key named like a secret before it builds a decision. A secret you place in a field with another name, such as a setting value, a policy or a draft's reason, is sent. Section 04 lists every field that goes. |
| No governed change commits without a decision | Holds, with limits | True for the writes the registration binds, on a gateway started with that registration, and every failure refuses the write. A gateway restarted without the registration is not governed: its heartbeat reports the registration missing, and ArtzAIn raises a finding for you. While ArtzAIn cannot answer, your host's user can open a break-glass window: the writes it lets through are journaled first, then receipted and reviewed (section 06). |
The sidecar, the connect command and the connect script are open source under the Apache License 2.0. You can read them at github.com/CogNEXUSlabs/cognexus-tools, under python/src/artzain/openshell/.
02 · Scope
What ArtzAIn does, and does not
ArtzAIn governs the changes your gateway makes to what your sandboxes may do. It governs the action, never the model.
Governed writes
- creating a sandbox, or deleting one;
- changing a sandbox's policy, or a setting;
- approving, rejecting, editing, undoing or clearing a policy draft;
- creating, changing or deleting a provider or its profiles, and rotating its credential;
- attaching a provider to a sandbox, or detaching it;
- exposing a service, or removing one;
- opening or revoking an SSH session.
What ArtzAIn does not do
- Sandboxing, Landlock, seccomp and credential injection stay in OpenShell.
- It does not see prompts, model input or output, or your sandboxes' traffic.
- It does not receive provider credentials, environment variables or file contents.
- It claims no proof for MCP, GraphQL, WebSocket, SQL or JSON-RPC traffic. Its policy prover covers filesystem, process, L4 and REST rules, and refuses to promote a bundle that relies on another protocol.
- It does not run your OpenShell. You run your own gateway, from NVIDIA's deb or rpm package, on Linux x86_64 or aarch64. The connect command can install that package for you, if you say yes (section 09).
03 · Trust boundaries
Two processes on your host, one connection out
Your gateway and the ArtzAIn sidecar run side by side as systemd services (beside the OpenShell snap's gateway, too), as launchd agents beside Homebrew's gateway on a Mac, or, for a gateway under Docker Compose, as two services of its Compose project. The only connection that leaves your host is the sidecar's outbound HTTPS to ArtzAIn.
Your host
Linux, OpenShell from its deb or rpm package
ArtzAIn
AWS us-west-2
| Boundary | What crosses it | Control |
|---|---|---|
| Gateway to sidecar | Each governed write, before it commits | A Unix socket, 0600 in a 0700 folder, so only your gateway's user can open it. Your gateway's package signs every call it makes with its own Ed25519 key (gateway_jwt), and the connect command gives the sidecar that key, so the sidecar refuses any call without your gateway's token. A gateway with no key goes unverified, which the sidecar logs at startup. Either way your gateway's user is the boundary: a process running as that user can read the signing key. |
| Gateway to sidecar, under Docker Compose | Each governed write, before it commits | The sidecar is a second service of your gateway's own Compose project, from the signed sidecar image of the same artzain release (section 09). The socket is on a volume both containers mount, 0600 and owned by the sidecar's user in a 0700 folder; your gateway's container runs as root, and the connect command refuses one that does not. The sidecar runs read-only, with no capabilities, on your host's network, so its routes are on your host's loopback. It checks your gateway's signed calls with the key gateway.toml names. Anyone who can use Docker on the host is root's equal there, and is the boundary. |
| Sidecar to gateway, under Docker Compose | The sidecar's openshell sandbox list and openshell status, and no other call | From artzain 0.6.46, the sidecar image's own openshell CLI calls the endpoint your host's CLI is registered with, which the connect command refuses unless it is http or https. The CLI runs with neither the gateway credential nor the sidecar's token in its environment, and holds no OpenShell identity of its own: your gateway answers it only as it would answer any process on the host. |
| Gateway to sidecar, the OpenShell snap | Each governed write, before it commits | From artzain 0.6.47. The snap lets its gateway connect only inside the snap's own folders, so the socket is there, 0600 and yours, in a folder of yours alone. Beside the snap's root gateway the sidecar is a system service that runs as you; as root it only makes that folder and copies the gateway's public key next to the socket. Its unit leaves out NoNewPrivileges, as it lists your sandboxes with the snap's CLI, which the snap starts through a setuid program. Anyone who can use sudo on the host is root's equal there, and is the boundary. |
| Gateway to sidecar, Homebrew's gateway on a Mac | Each governed write, before it commits | From artzain 0.6.48. The gateway and the sidecar are launchd agents of yours: the gateway as brew services runs it, the sidecar from ~/Library/LaunchAgents. A Mac has no runtime folder for sockets, so the socket is under your state folder, 0600, in a folder of yours alone. The sidecar checks the gateway's signed calls with the key the formula copies for it. launchd starts the two in no order: a gateway that starts first refuses every write until the sidecar answers. You are the boundary, as on a package host. |
| Local processes to sidecar | The sidecar's loopback HTTP routes | A sidecar holding a gateway credential answers nothing but /healthz unless the caller presents the sidecar's own random token, compared in constant time. The connect command writes that token. |
| Sidecar to ArtzAIn | Decisions, reports, heartbeats, your base policy | Outbound HTTPS to one origin. The client refuses any other origin, follows no redirect, and reads at most 256 KiB of an answer. Only the gateway credential authenticates it. |
| Your team to ArtzAIn | Connect requests, approvals, revokes | A signed-in dashboard session. An approval is itself a sealed decision, under separation of duties (section 05). |
04 · Data flows
What leaves your host, and what we keep
Every flow that crosses a boundary, when it happens, and what ArtzAIn keeps from it.
| Flow | When | What is sent | What ArtzAIn keeps |
|---|---|---|---|
| You ask for a connect | Once per gateway | A display name and the configuration: OpenShell release, interceptor and decision timeouts, telemetry choice | The request; the gateway's id, which ArtzAIn assigns (gw_<ulid>); a sealed decision |
| An owner or admin approves | Once | The approval. An account on its own adds a written attestation | A sealed decision |
| ArtzAIn shows you the command | On "Issue the command" | The enroll token, shown once and marked not to be cached | The token's peppered SHA-256 only |
| Your host installs | When the command runs | Downloads only, from GitHub and PyPI: the connect script, uv, and the wheels the script names by SHA-256. On a host without OpenShell, and only if you say yes, NVIDIA's OpenShell packages, each named by SHA-256 | Nothing |
| Your host redeems the token | Once | The enroll token, and the digest of the configuration you approved | When it was used, and from which address. You see both on your dashboard. Deleting your account clears the address |
| The sidecar asks for a decision | Each governed write | Your gateway as the agent (openshell:<gateway>), the action and target, and a payload: the method and the write's facts (sandbox id and name, the policy or the setting key and value, a draft's ids, reason or proposed rule, the provider, service, port and domain). Keys named like a secret are dropped and sizes are capped. No principal, prompt, credential, environment variable or file | The sealed receipt: agent, action, target, verdict, the Artzain crew's votes, the bundle version, and the payload's SHA-256, not the payload |
| The sidecar reports a commit | After a governed create or policy update commits | Sandbox id, policy hash, decision id, method | The projection that drift is checked against |
| Heartbeat | Every minute | Sidecar and OpenShell versions, the installed registration's digest, what gateway.toml holds now, decision latency (p50 and p95), undelivered reports | The latest values |
| Inventory | Every five minutes, and on change | Each sandbox's id, name, phase and effective policy hash | Catalog rows, and drift findings |
| The sidecar fetches your base policy | At start, and every five minutes | Nothing. It receives your team's compiled base policy, its digest and the prover's result | Nothing new |
| OpenShell's own telemetry | Only if you turn it on | OpenShell's own data, to NVIDIA. ArtzAIn only writes your choice into the gateway's settings | Nothing. The sidecar sends nothing to anyone but ArtzAIn |
| ArtzAIn reads OpenShell advisories | Hourly | Nothing about you. ArtzAIn reads NVIDIA's published list | A finding on each of your gateways running an affected release |
| Your host sends its break-glass journal | After a break-glass window, once ArtzAIn answers | Each window's length, reason and opener (your host's user name), and each write it let through: the method, the action and target ArtzAIn would have decided, the payload's SHA-256, the operation digest, the caller's subject id, kind and provider, and the request id | Flagged receipts, not billed; a Review queue item for each window; each window's reason and opener, cleared when you delete your account |
The sidecar logs no payload, target, key or body. It logs a failure by its kind, and logs how it reaches ArtzAIn without the credential.
05 · Credentials
Credentials and approvals
Two credentials, each with one job: a short-lived enroll token that connects a gateway once, and the gateway credential the sidecar uses after that.
The enroll token
cnxt_and 256 random bits. It is valid for 30 minutes and works once.- ArtzAIn stores only its peppered SHA-256, and redeems it under a row lock, so two redeems at once yield one credential.
- It is bound to the digest of the configuration you approved. A different configuration is refused, and the token is not spent. Issuing a new token retires the earlier one.
- The command that carries it is four lines joined by
&&. A failed download, or a script whose SHA-256 is not the pinned one, stops it before the token is exported or anything runs. - It goes to ArtzAIn over HTTPS only. Plain
http://is refused unless the engine runs on the same host.
The gateway credential
cnxg_and 256 random bits: a key kind of its own, stored as a peppered hash. It never works as an account key.- It may call ten routes and no others: decisions, the commit report, announcing the gateway, and, for its own gateway only, its inventory, heartbeat, break-glass journal, base policy, revoke and the two key-rotation routes.
- A decision must name the credential's own gateway as agent and as target. ArtzAIn refuses anything else before the engine runs, so nothing is sealed, whatever your account's identity-binding setting.
- It does not expire. You rotate it (at most two live keys during a rotation) and you revoke it.
On your host
- The credential lives in
~/.config/artzain/openshell/sidecar.env: mode0600, in a0700folder. The sidecar's own token sits beside it. - systemd passes it to the sidecar as an
EnvironmentFile. The sidecar's unit setsUMask=0077andNoNewPrivileges=yes. - Your gateway's binary is asked its version without the credential in its environment.
Revocation
A revoke takes effect on the next call: the gateway's keys get 401. You can revoke three ways:
artzain connect openshell removeon the host, which also restores your gateway's files;- Revoke… on your dashboard;
- deleting your account.
Approval
- On a team, the owner or admin who asked for a connect cannot approve it.
- An account on its own approves with a written attestation.
- The approval is itself a sealed decision in your ledger.
06 · Threat model
What we defend against, and what remains
Each threat, the control as built, and what is left. We list the residuals plainly so you can weigh them.
| Threat | Control as built | What remains |
|---|---|---|
| The enroll token leaks (shell history, a CI log, a screenshot) | 30 minutes, one use, bound to the approved configuration, passed by environment. You see where and when it was used, and can revoke. | Within its 30 minutes, whoever runs it first binds a gateway of their own to that configuration. Spotting and revoking it is yours. |
| The gateway credential is stolen from the host | Ten routes, its own gateway only. Rotate and revoke. A file only its owner reads, and never logged. | Anyone with the host user's access can decide as that gateway until you revoke it. The credential does not expire. |
| A compromised host forges receipts for another gateway or tenant | ArtzAIn assigns the gateway id. Agent and target must be the credential's own gateway, checked before anything is sealed. | None found |
| A local process talks to the sidecar | The socket is your gateway user's alone. The loopback routes need the sidecar's token. Every call must carry your gateway's signed token (gateway_jwt). | Any process running as your gateway's user can read the gateway's signing key, and so call the socket. That user is the boundary. |
The interceptor is removed from gateway.toml | The heartbeat reports what gateway.toml holds. Anything but the installed registration raises a finding, in your dashboard's bell and by webhook. Policy drift is checked independently, sandbox by sandbox. | A gateway started from another configuration file is not seen this way. Your host's administrator can always unbind their own gateway: ArtzAIn detects it, and cannot prevent it. |
| Automatic approval of policy proposals is turned back on | Any approval mode but manual is denied at any scope, by a vote no bundle can soften. The connect command sets the gateway-wide mode to manual first. | None found |
| Supply chain | See section 09. | The connect script is checked by its SHA-256, not signed. The signed compatibility manifest names it by that SHA-256, and upgrade runs only that script. |
An old or altered compatibility list is served to upgrade | artzain connect openshell upgrade checks the list's signature with cosign, itself pinned by SHA-256, against our release workflow's identity, before it fetches anything the list names. It refuses a list whose serial is not its release's, or is older than the last one your host read, and a connect script that is not the one the list names. | A host that has not read a newer list yet can be shown an older signed one as the newest, and then moves only to what that list allows. It never moves to a pair no signed list names. |
| The connect command installs OpenShell as root | Only on a host without OpenShell, and only when you answer yes at the terminal or pass --install-openshell. Otherwise it prints the commands and stops, before your token is spent. Every package is checked against a SHA-256 pinned in artzain before sudo runs. | The packages then run as root as NVIDIA built them, as a manual install does. sudo may keep your password for the rest of the session. |
| ArtzAIn is down or slow | Every governed write is refused. Running sandboxes keep their policy. Your host's user can open a break-glass window of up to 240 minutes: a write ArtzAIn gave no answer for goes through, journaled first, and is sealed as a flagged receipt and reviewed once ArtzAIn answers. A deny, a review, a rate limit, a refused credential and a gateway-wide write still refuse. | Writes in a window go unchecked until you review them. A host user who rewrites the journal before ArtzAIn sees it can leave writes out: a journal that stops continuing is flagged, and drift still shows each sandbox it changed. |
| Flooding denied writes to run up your bill | Each gateway has its own hourly bucket. Over it, the write is refused. | Within the bucket, denials are billed like any decision. |
| The sidecar image a Compose host runs is swapped: a moved tag, a registry serving another image | The connect command checks the image of its own release with cosign, itself pinned by SHA-256, against our release workflow's identity, before your token is spent, and runs it by the digest it verified. | An image you name yourself (--sidecar-image, by its digest) is not checked, and the command says so. A host that cannot reach Sigstore cannot verify, and so cannot connect under Compose. |
| The gateway credential on a Compose host | The same file only its owner reads, which Docker Compose reads as the sidecar's environment. The connect command never prints your project's resolved configuration. | The credential is in the sidecar container's environment: docker inspect shows it to anyone who can use Docker on the host, who is root's equal there. |
| A snap refresh moves OpenShell off the release you approved | The connect command holds the snap's refreshes, so the snap does not refresh itself, and remove lifts only a hold it put. doctor warns when the hold is gone or the snap was refreshed, and fails when its release is off the approved line. | A hold stops automatic refreshes only: snap refresh openshell, run with sudo, still moves it. |
| The snap's gateway mode is switched | The other mode's gateway reads another gateway.toml, without the registration: doctor fails when the snap runs its gateway in another mode than the one you connected. | Until you run doctor, nothing tells ArtzAIn, and that gateway's writes go ungoverned. |
Homebrew's gateway reads another gateway.toml | The formula reads yours, in ~/.config/openshell, once there is one, and else its own: a file you add after connecting holds no registration. doctor fails when the gateway now reads another file than the one you connected. | Until you run doctor, nothing tells ArtzAIn, and that gateway's writes go ungoverned. |
A gateway.env points Homebrew's gateway at another configuration | The connect command refuses one that sets OPENSHELL_GATEWAY_CONFIG, before it spends the token. | A line added after connecting unbinds the gateway, as above. |
Your own docker compose unbinds the gateway | The connect command adds its own compose file to COMPOSE_FILE in your project's .env, so docker compose up -d in the folder keeps your gateway bound; a gateway recreated without the sidecar's socket refuses every governed write. doctor fails when docker compose up -d there would recreate the gateway otherwise than it runs. | A docker compose -f that names other files recreates the gateway without the socket: governed writes are refused until you run the connect command again. |
| Personal data in the principal | Not sent: the decision carries no principal. | Names, a draft's reason and a proposed rule are your own text, and are sent. |
07 · Failure
When something fails, the write is refused
The registration that decides fails closed. The one that observes, which reports after the commit, fails open and never decides. Our conformance run proves each row below on a real OpenShell gateway.
| Failure | What your gateway is told |
|---|---|
ArtzAIn's verdict is not allowdenyreview | PERMISSION_DENIED, with the decision id |
| ArtzAIn is unreachable, times out, or answers with an error, a redirect or something unreadable | UNAVAILABLE: refused |
| ArtzAIn gives no answer, or a 5xx, while your host has a break-glass window open | Allowed, once the sidecar has journaled it. It becomes a flagged receipt, and the window a review, when ArtzAIn answers |
| The gateway's hourly bucket is used up | RESOURCE_EXHAUSTED, with when to try again: refused |
| The sidecar is down | Your gateway refuses on its own, and will not start while its interceptor does not answer |
| A gateway-wide policy write | Refused by the sidecar, without asking ArtzAIn |
| A sandbox created without a policy while the base policy is unknown | Refused |
| The commit report cannot be delivered | Kept in the sidecar's journal and retried. The write has already committed |
08 · Integrity
Integrity over time
Connecting once is not enough. ArtzAIn keeps checking that your gateway stays bound, and tells you when it does not.
- A silent gateway. Five minutes without a heartbeat raises
openshell_gateway_silent. The next heartbeat resolves it. - The registration. At each heartbeat the sidecar reads
gateway.tomland reports the digest of the registration it finds, or that it ismissingorunreadable. ArtzAIn compares that with the registration the sidecar was installed for, and raisesopenshell_registration_changedwhen they differ. - Drift. Each sandbox's effective policy hash is compared with what ArtzAIn last allowed.
- OpenShell advisories. ArtzAIn reads NVIDIA's published security advisories hourly, and a gateway on an affected release gets a finding. Our response is due within two business days, with a conformance run on the fixed release.
doctor, which you run on your host, checks the registration, the socket's and the credential file's modes, the sidecar's token, the clock, and the route to ArtzAIn.
09 · Supply chain
Supply chain, and how to check it yourself
Every piece that reaches your host is pinned by its hash, and you can check each one yourself.
| Piece | Pinned and checked |
|---|---|
| The connect script | Your dashboard pins its version and SHA-256, and the command checks it before anything runs. The release also carries a .sha256 file beside the script. |
| uv, which the script runs | Its version, and each build's SHA-256, are written into the script. A build with another hash is refused. |
| artzain and its dependencies | Every wheel by its SHA-256, in an environment of the script's own: uv pip install --require-hashes --only-binary :all:. The artzain wheel carries PyPI provenance (PEP 740) from CogNEXUSlabs/cognexus-tools, workflow publish-pypi.yml, environment release. |
| The sidecar image | Its base image is pinned by digest, and every wheel installs by hash. It is signed keyless with cosign by sidecar-image.yml on a sidecar-v* tag, and carries an SPDX SBOM attestation. Built for amd64 and arm64. On a gateway under Docker Compose, the connect command checks that signature itself, with cosign pinned by SHA-256, and runs the image by the digest it verified. |
The openshell CLI in the sidecar image | From artzain 0.6.46, NVIDIA's static build of one OpenShell release, each platform's named by SHA-256 in openshell.lock. It is downloaded outside the image build and kept only if its SHA-256 matches; the build checks it again, and refuses one that is not the lock's release. The image's signature and SBOM cover it. Compare the values with NVIDIA's openshell-checksums-sha256.txt for the release. |
| The OpenShell snap | The connect command does not install it. The snap store signs each revision; our conformance runs install pinned revisions, each file checked by its SHA-256. |
| The OpenShell Homebrew formula | The connect command does not install it. NVIDIA's release publishes the formula, which pins each binary it installs by SHA-256; our macOS conformance run installs it by the file's SHA-256. |
| OpenShell | On a host without it, and only if you say yes, the connect command installs NVIDIA's deb or rpm packages of the pinned release, each checked against a SHA-256 pinned in artzain (artzain.openshell.install) before anything runs as root. Compare those values with NVIDIA's openshell-checksums-sha256.txt for the release. On any host, the command checks the installed release is the approved one (same minor line), and our conformance runs pin the deb by SHA-256 and run the install on a host with no OpenShell. |
| The compatibility list | Which artzain release passed our conformance runs with which OpenShell release, and each release's connect script by its SHA-256. Signed keyless at each compat-v release of CogNEXUSlabs/cognexus-tools; upgrade checks the signature before it moves your gateway. |
| Publishing | Every release tag waits for a named approver before anything publishes. |
Check it yourself
For the self-hosted engine's own images, see verifying a release on the install page.
10 · Figures
Figures
Taken from the code of artzain 0.6.48 and the hosted engine. A test holds each figure in our review pack to the code, so a change that makes one wrong fails our build.
| Figure | Value |
|---|---|
| Enroll token | cnxt_ and 256 random bits; 30 minutes; used once |
| Redeems from one address | 30 an hour |
| Gateway credential | cnxg_ and 256 random bits; no expiry; at most 2 live keys |
| Key rotations per gateway | 12 an hour |
| Governed writes per gateway | your plan's hourly rate, at most 600 an hour; bursts up to 10 times the rate |
| Interceptor timeout (your gateway's) | 1500ms |
| Decision deadline (the sidecar's) | 1200ms |
| Heartbeat | every 60s; silent after 300s |
| Inventory | every 300s and on change; at most 200 sandboxes |
| Gateway socket | 0600, in a 0700 folder |
| Answer the sidecar reads from ArtzAIn | at most 256 KiB |
| Decision payload | strings cut to 500 characters, lists to 40 items, nesting to 8; 200000 characters in all |
| A review's approval, remembered | 24 hours, 1024 entries, in memory only |
| uv the connect script runs | 0.8.15, checked by SHA-256 |
| Python of the connect environment | 3.12 |
| Connect script | connect-0.6.48.sh, SHA-256 948e552158da95f2bb6c2f71ced378111bdc5bfdb35e83e93e24f2534641941f |
| Sidecar image | sha256:2c6232a310fbf5a9f74f35fa904081b94b62def845756bb48d3df373e9243efa (artzain 0.6.48) |
| OpenShell release approved by default | 0.1.2 |
| OpenShell packages the connect command can install | 0.1.2: the deb for amd64 or arm64, or 3 rpms for aarch64 or x86_64; each by SHA-256 |
cosign upgrade checks the compatibility list with | v2.6.5, by SHA-256, for Darwin arm64 and Linux aarch64 and Linux x86_64 |
| The sidecar image the connect command runs under Compose | its own release's, checked with cosign v2.6.5 against sidecar-image.yml at sidecar-v<release>, run by digest |
The openshell CLI in the sidecar image | OpenShell 0.1.3: NVIDIA's static build for aarch64 or x86_64; each by SHA-256 |
| Our response to an OpenShell advisory | 2 business days |
11 · Hosting
Where ArtzAIn runs
The engine, your ledger and the key that signs your receipts, as our infrastructure code defines them.
- The engine runs on AWS in us-west-2.
- Its PostgreSQL database is not publicly reachable, is encrypted at rest, keeps 7 days of backups, and has deletion protection.
- The key that signs your receipts is held wrapped by a KMS key, with rotation on.
- Your sidecar reaches the engine through Cloudflare, which ends TLS and applies the WAF and rate limits, and then a load balancer that accepts TLS 1.2 and 1.3. Cloudflare therefore sees what the sidecar sends, in transit.
- Only our Cloudflare zone can reach the engine. Cloudflare presents a client certificate that our own certificate authority signed, and our load balancer refuses any connection without it (mutual TLS). A site in another Cloudflare account that points at our load balancer fails at the handshake, so nobody can route around our WAF and rate limits.
- Our status page, status.cognexuslabs.ai, publishes the decision API's and connect's availability.
12 · Fixed in 0.6.41
What writing this review found, and fixed
Holding this review to the code found five gaps. We fixed each with a test that failed first, and shipped the fixes in artzain 0.6.41 and its sidecar image.
| Gap | Now |
|---|---|
| The sidecar's loopback port answered any local caller, as your gateway | A sidecar holding a gateway credential needs its own token on every route but /healthz |
| The dashboard's command could go on after a failed download or SHA-256 check | Its lines are joined by &&, so a failure stops it before the token is exported |
Removing the registration from gateway.toml raised nothing | The heartbeat reports what the file holds, and ArtzAIn raises a finding |
| The install on a deb or rpm host pinned artzain's version, not any wheel's hash | Every wheel is installed by its SHA-256 |
Smaller items: where a token was used from was not shown, and the address was kept after account deletion; the credential was in the version check's environment; plain http:// engines were accepted | Each fixed |
A gateway you connected with artzain 0.6.40 or earlier keeps working, but does not get these fixes, or break-glass, until you run the current connect script (0.6.48) on its host again, as the gateway's user. It needs no new enroll token:
upfinds the credential it saved.The run installs the hash-locked environment, gives the sidecar its token and its view of
gateway.toml, and restarts the sidecar once, with your gateway. Until then, that sidecar does not report its registration, so ArtzAIn cannot tell you if it is removed.
13 · Open items
Open items, and the independent review
What is not done yet, said plainly.
| Item | State |
|---|---|
| An independent review of enroll and credential handling | PlannedIts scope and questions are below. |
| Signing the connect script and the compatibility manifest | Manifest signedThe compatibility manifest is signed at each compat-v release, and upgrade checks it before it moves your gateway. The connect script is checked by its SHA-256, which the signed manifest names; the script itself is not signed. |
gateway_jwt on deb and rpm hosts | OnThe package signs every call, and the connect command gives the sidecar its key. Your gateway's user can read the key, so that user stays the boundary. |
| Kubernetes gateways | Not supported yetThe sidecar image is published for them. |
| The OpenShell snap's gateway | ConnectsFrom artzain 0.6.47, in both of the snap's gateway modes: its root service (OpenShell 0.1.3, and 0.1.4's system mode) and its user service (0.1.4's user mode). The connect command holds the snap's refreshes. A switch of the snap's gateway mode leaves the gateway ungoverned until doctor finds it. Pick snap in the dashboard's connect steps. |
| Homebrew's gateway on a Mac | ConnectsFrom artzain 0.6.48, on a Mac with Apple silicon, beside the gateway NVIDIA's formula runs with brew services. A gateway.toml you add in ~/.config/openshell after connecting leaves the gateway ungoverned until doctor finds it. Pick Homebrew in the dashboard's connect steps. |
| A gateway under Docker Compose | ConnectsThe connect command binds it, as NVIDIA's own Compose project runs it. From artzain 0.6.46, the sidecar image carries NVIDIA's openshell CLI: the sidecar lists every sandbox, and its heartbeat carries your gateway's OpenShell release, so OpenShell advisories reach it. A gateway you connected with 0.6.45 gets both when you run the connect command, or upgrade, on its host again. Pick Docker Compose in the dashboard's connect steps. |
| Gateway credentials expire | No. You rotate and revoke them. |
| OpenShell leaves secret fields out of interceptor calls | Not verified by usThe sidecar strips secret-named keys itself. |
| The address a token was used from | Kept while your account lives, and shown to you. Cleared when the account is deleted. |
Independent review: scope
How a gateway gets and uses its credential:
- issuing, carrying and redeeming the enroll token;
- the gateway credential: minting, its route allowlist and binding, rotation, revocation;
- the sidecar's local surfaces: the socket, the loopback routes and their token;
- the connect script's install path.
Independent review: questions
- Can an enroll token be redeemed twice, or for a configuration other than the one approved?
- Can a gateway credential decide as, report for, or revoke another gateway, or reach any route beyond its ten?
- Can a local user who is not the gateway's user reach the sidecar's decisions?
- Can anything the connect script installs differ from what it names by hash?
- Does any log line, error message or answer carry an enroll token, a credential or the sidecar's token?
- On a team, can the person who asked for a connect also approve it?
Reporting a vulnerability
Email security@cognexuslabs.ai, and please keep an unfixed defect out of public issues. We acknowledge a report within 3 business days and aim for a fix and coordinated disclosure within 90 days. The full policy is SECURITY.md in the cognexus-tools repository.
Next step
Bring this page to your security review.
We walk your security team through it, and answer what it leaves open.