Runtime secret injection with process-level isolation — built for the AI-agent era.
Project description
RSIL — Runtime Secret Isolation Layer
Runtime secret injection with process-level isolation — built for the AI-agent era.
The Problem
Modern development workflows have introduced a new threat model that existing tools were not designed for:
-
.envfiles get committed to Git. Even with.gitignore, accidental pushes happen. Secrets end up in history, forks, and CI logs. -
AI coding agents read your entire workspace. Tools like Claude Code, Cursor, and GitHub Copilot run inside your local repository and have read access to every file, including
.env. -
Environment variables are globally visible. Any process on the same machine can read another process's environment via
/proc/<pid>/environorps e. -
Existing tools don't protect against this. HashiCorp Vault, Doppler, and 1Password solve secret storage, but they still assume your local machine is a trusted environment. That assumption no longer holds.
The Solution
RSIL introduces a new model: secrets never exist on disk in plaintext, and only exist during controlled execution.
# Instead of this:
export STRIPE_KEY=sk_live_abc123
python app.py
# Do this:
rsil run --service payment-api -- python app.py
RSIL:
- Stores secrets encrypted at
~/.rsil/secrets.enc(Fernet AES-128-CBC + HMAC) - Decrypts secrets only at runtime, in memory
- Spawns your process via
fork()/execve()with a minimal, isolated environment - Streams stdout/stderr through a redaction layer (secrets never appear in logs)
- Zeroes all secret data from memory after the process exits
- Inspects the process tree to block AI agents from triggering secret injection
Features
- No
.envfiles — secrets are never stored in plaintext on disk - Runtime-only injection via POSIX
fork()/execve() - Minimal environment — child process receives only what it needs (
PATH,HOME, and your secrets) - Process-level caller inspection — deny AI agent processes by name
- Stdout/stderr redaction — secret values are replaced with
***REDACTED***in all output - Automatic memory cleanup on exit (overwrite + GC)
- Encrypted local store with Fernet (AES-128-CBC + HMAC-SHA256)
- Audit log at
~/.rsil/audit.log(JSON-lines) - Policy engine for fine-grained process-level access control (v0.4)
How It Compares
| Feature | Vault | Doppler | direnv | RSIL |
|---|---|---|---|---|
| Central secret storage | ✅ | ✅ | ❌ | ✅ |
| Runtime injection | ✅ | ✅ | ✅ | ✅ |
| Local dev focus | ⚠️ | ✅ | ✅ | ✅ |
| No network dependency | ❌ | ❌ | ✅ | ✅ |
| AI agent protection | ❌ | ❌ | ❌ | ✅ |
| Process-level isolation | ❌ | ❌ | ❌ | ✅ |
| Output redaction | ❌ | ❌ | ❌ | ✅ |
| No plaintext on disk | ✅ | ✅ | ❌ | ✅ |
The last three rows are RSIL's moat.
Installation
pip install rsil
Or with uv:
uv add rsil
Then initialize RSIL (creates ~/.rsil/ and generates your master key):
rsil init
Quick Start
# 1. Initialize (one-time setup)
rsil init
# 2. Add secrets
rsil add STRIPE_KEY=sk_live_yourkey --service payment-api
rsil add DATABASE_URL=postgres://localhost/mydb --service payment-api
# 3. Verify (shows keys, never values)
rsil list --service payment-api
# 4. Run your app
rsil run --service payment-api -- python app.py
# With uvicorn
rsil run --service payment-api -- uvicorn main:app --reload
Your application reads secrets normally via os.environ:
import os
stripe_key = os.getenv("STRIPE_KEY") # injected at runtime by RSIL
No .env file. No export. No risk.
CLI Reference
rsil init
Initialize RSIL. Creates ~/.rsil/ and generates master.key.
rsil init
rsil add
Add or update a secret.
rsil add KEY=value --service SERVICE_NAME
| Flag | Description |
|---|---|
--service |
Service name to scope the secret to (required) |
rsil list
List secret keys for a service. Never shows values.
rsil list [--service SERVICE_NAME]
| Flag | Description |
|---|---|
--service |
Filter by service name (optional — shows all if omitted) |
rsil delete
Delete a secret.
rsil delete KEY --service SERVICE_NAME
rsil run
Run a command with secrets injected.
rsil run [--service SERVICE_NAME] [--no-redact] -- COMMAND [ARGS...]
| Flag | Description |
|---|---|
--service |
Service name to load secrets from |
--no-redact |
Disable output redaction (use only for debugging) |
The -- separator is required to separate RSIL flags from the command.
Architecture
rsil run --service payment-api -- python app.py
|
v
cli/commands/run.py
|
v
core/executor.py :: Executor.run()
|
+--[1] security/process_guard.py check parent process
| if parent in AI_BLOCKLIST → deny
|
+--[2] policy/engine.py evaluate access rules
| (stub in v0.1, active in v0.4)
|
+--[3] secrets/manager.py decrypt ~/.rsil/secrets.enc
| → {"STRIPE_KEY": "sk_live_..."}
|
+--[4] core/env_builder.py build minimal env
| → {"STRIPE_KEY": "...", "PATH": "...", "HOME": "..."}
| NEVER copies os.environ
|
+--[5] core/process.py os.fork() + os.execve()
| child: disable core dumps → exec
| parent: pipe stdout/stderr through Redactor
|
+--[6] core/cleanup.py destroy() — zero secrets, gc.collect()
|
+--[7] security/audit.py write JSON event to audit.log
Key modules
| Module | Responsibility |
|---|---|
rsil/cli/ |
typer-based CLI, one file per command |
rsil/core/executor.py |
Lifecycle orchestration |
rsil/core/process.py |
POSIX fork/execve, pipe-based I/O |
rsil/core/env_builder.py |
Minimal environment construction |
rsil/secrets/ |
Encrypted store, Fernet crypto, SecretManager |
rsil/security/process_guard.py |
AI agent detection via psutil |
rsil/security/redact.py |
Stdout/stderr secret redaction |
rsil/policy/ |
YAML-based access control rules (v0.4) |
Security Model
What RSIL protects against:
- Accidental
.envfile commits to Git - AI coding agents reading
.envoros.environduring a session - Secrets leaking into stdout/stderr logs
- Secrets persisting in the parent process environment after execution
- Core dump files containing secret values
What RSIL does NOT protect against:
- A root-level attacker on the same machine
- Memory scraping by a privileged process
- Secrets that your own application logs explicitly
- Network-level interception (RSIL is a local tool, not a network proxy)
- Compromised Python interpreter or standard library
RSIL is a local runtime isolation layer, not a remote secrets manager. Use it alongside (not instead of) proper secret management for production deployments.
Roadmap
See docs/roadmap.md for the full week-by-week plan.
| Version | Goal |
|---|---|
| v0.1 | CLI + encrypted store + basic fork()/execve() execution |
| v0.2 | Process guard + minimal env + integration tests |
| v0.3 | Pipe-based secret injection (experimental) |
| v0.4 | Policy engine + FastAPI example |
Contributing
See CONTRIBUTING.md.
License
MIT — see LICENSE. Copyright Sentivs 2026.
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 rsil-0.1.0.tar.gz.
File metadata
- Download URL: rsil-0.1.0.tar.gz
- Upload date:
- Size: 41.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5258b711a4876b042e6afb41a98c26e06c9f05cf95888f94b000a0c83be277bc
|
|
| MD5 |
64ef1de0376860becc380d48cee89263
|
|
| BLAKE2b-256 |
844d5384ed92029372aa179b5aeb87900cc2f5e58fae861cca6e00e966f77fef
|
Provenance
The following attestation bundles were made for rsil-0.1.0.tar.gz:
Publisher:
publish.yml on Sentivs-co/rsil
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rsil-0.1.0.tar.gz -
Subject digest:
5258b711a4876b042e6afb41a98c26e06c9f05cf95888f94b000a0c83be277bc - Sigstore transparency entry: 1280908081
- Sigstore integration time:
-
Permalink:
Sentivs-co/rsil@7cd183eeab1a442e4b06ad56305d1a3d84e92fed -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Sentivs-co
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7cd183eeab1a442e4b06ad56305d1a3d84e92fed -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file rsil-0.1.0-py3-none-any.whl.
File metadata
- Download URL: rsil-0.1.0-py3-none-any.whl
- Upload date:
- Size: 28.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5c452e6d7a9df9022e72bb520c02ec43fbec25632f8dcc66f23d5a47eff1463
|
|
| MD5 |
f76214165302a9a22ff865befaa900c2
|
|
| BLAKE2b-256 |
c17d4e25de704c1294bd003ab64482deb362121cbf192ef10ec3c7e6b0f421f4
|
Provenance
The following attestation bundles were made for rsil-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Sentivs-co/rsil
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rsil-0.1.0-py3-none-any.whl -
Subject digest:
a5c452e6d7a9df9022e72bb520c02ec43fbec25632f8dcc66f23d5a47eff1463 - Sigstore transparency entry: 1280908085
- Sigstore integration time:
-
Permalink:
Sentivs-co/rsil@7cd183eeab1a442e4b06ad56305d1a3d84e92fed -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Sentivs-co
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7cd183eeab1a442e4b06ad56305d1a3d84e92fed -
Trigger Event:
workflow_dispatch
-
Statement type: