Skip to Content
Remote ExecutorsSecurity & networking

Security & networking

The page to send to whoever has to approve running this inside your network.

Networking

The executor makes one outbound connection and nothing else listens. It opens a WebSocket over TLS to your project’s wss://exec-… address and keeps it alive. Work arrives on that existing connection.

That means:

  • No inbound firewall rules. Nothing on your side accepts connections.
  • No public IP, no DNS entry, no load balancer for the executor.
  • No open ports. The agent doesn’t run a server.
  • Egress only — outbound HTTPS to qraptor.app on port 443.

If your egress is filtered, allow outbound HTTPS to your project’s exec-… host. Some proxies permit HTTPS but block WebSocket upgrades; that’s the usual cause of a connection that never establishes.

Authentication

Three layers, all active at once.

Connection. The executor presents its API key when it connects. qRaptor stores only a SHA-256 hash — the key itself exists only in your deployment configuration. Keys are scoped to a single project: a key from one project is refused against another’s URL (PROJECT_MISMATCH).

Per message. Every message the executor sends carries an HMAC-SHA256 signature with a timestamp and a one-time nonce. Timestamps outside a five-minute window are refused (CLOCK_SKEW), and a repeated nonce is refused (NONCE_REPLAY) — so a captured message can’t be replayed.

Transport. TLS by default. Mutual TLS is available if you want the platform to verify a client certificate as well: set QRAPTOR_MTLS_ENABLED=true with QRAPTOR_MTLS_CERT_FILE, QRAPTOR_MTLS_KEY_FILE, and optionally QRAPTOR_MTLS_CA_FILE to pin the server’s CA.

Connection attempts are rate-limited per key, so a leaked key can’t be used to hammer the gateway.

What crosses the boundary

ℹ️

Secrets are resolved before dispatch. When a tool needs a connection string, an API key or an auth header, qRaptor substitutes the value on the platform and sends the finished request. The executor never reads your secret store, has no credentials for it, and can’t enumerate what’s in it.

Platform → executor: the script or tool definition to run, its input values, and any secrets already substituted into that specific call.

Executor → platform: the result, log lines your code produced, error messages, and a periodic heartbeat carrying host metrics (CPU, memory, disk, active and queued jobs, uptime) plus basic system info (OS, architecture, Python version, memory, CPU count).

Never sent: anything your script read but didn’t return. Query results, file contents and API responses stay on your side unless your code makes them the result.

Note the implication for logging — anything written to console.log() is streamed back and stored in the run history. Treat it like any other application log and don’t print secrets or personal data.

Execution isolation

Scripts run in a separate operating-system process, spawned fresh for each execution. A script can’t reach the agent’s own memory, its API key, or another execution’s state. Each has a time limit (EXEC_TIMEOUT_SEC) and a memory ceiling (MAX_MEMORY_MB), and there’s a size limit on scripts (MAX_SCRIPT_SIZE_KB).

The official container image runs as a non-root user.

⚠️

Process isolation is not a sandbox. A remote script runs with the permissions of the executor process on your host and can reach anything that host can reach. Give the executor its own machine or container with least-privilege network access and credentials — the same way you’d treat any service that runs code. Don’t run it somewhere with broad access it doesn’t need.

Restricting what an executor will run

Four environment variables control what the agent is willing to accept, independently of what qRaptor sends:

VariableEffect
ENABLE_SYSTEM_TOOLSSet false to refuse qRaptor’s built-in tools.
ENABLE_USER_TOOLSSet false to refuse your project’s own tools.
ALLOWED_TOOL_KEYSComma-separated allowlist. Anything not listed is refused.
BLOCKED_TOOL_KEYSComma-separated blocklist.

These are enforced on your side, so they hold regardless of what anyone configures in Studio. A useful pattern for a sensitive host: allowlist the specific tools it exists to run, and refuse everything else.

Outbound requests from the executor

HTTP tools running on an executor are checked before the request goes out. Cloud metadata endpoints are blocked by default — 169.254.169.254/32 and fd00::/8 — which stops a tool being used to read instance credentials. Extend the blocklist with QRAPTOR_BLOCKED_OUTBOUND_CIDRS to cover internal ranges the executor has no business reaching.

Key rotation

Keys can be rotated from Studio without downtime; the old key stays valid for a grace period while you update the executor. See API keys.

For scheduled rotation, point the agent at a file with QRAPTOR_API_KEY_FILE instead of setting QRAPTOR_API_KEY directly. It can then reload a new key without a full restart, which suits a secret manager that rewrites the file.

File transfers

Files can move between the executor and qRaptor’s document storage in either direction, in verified chunks with SHA-256 checksums. Fixed limits apply: 50 MB for an upload from the executor, 512 MB for a download to it. Download paths are validated so a transfer can’t be directed outside the download directory.

Availability

Run more than one executor for redundancy. Unpinned work is spread across whichever executors are online, so losing one doesn’t stop work as long as another is up. Give each its own API key, and use Drain before planned maintenance so in-flight jobs finish rather than being cut off — see Manage executors.

Next

  • Overview — back to the top of the section.