AI agents should not have unrestricted access to your filesystem.
cryptofs sits in between: the agent only ever sees opaque object IDs and
short-lived signed tokens instead of real paths or filenames. Destructive actions
(delete) require explicit human approval before a token can be minted.
- Python 3.7+
- For Openclaw integration: Openclaw installed with a running gateway
git clone https://github.com/Yukyin/gatekeeper.git
cd gatekeeper
chmod +x bin/cryptofs
bash demo.sh # full end-to-end walkthrough
bash test_expiry.sh # verify token expiry is enforcedBoth scripts are self-contained and clean up after themselves.
index -> list -> mint token -> exec (low-risk: view, list)
index -> list -> request -> approve -> mint-approved -> exec (high-risk: delete)
- Index a directory: files are registered in SQLite and assigned opaque
oids. Real paths never leave the DB. - Mint a short-lived, single-use, HMAC-signed token bound to a specific
oidand action. - Exec the token: cryptofs re-validates the inode binding, checks the nonce, then performs the action.
- Delete requires request to approve before a token can be minted. Each approval is single-use.
This is a complete walkthrough from zero to a working agent that can only access files through cryptofs.
chmod +x bin/cryptofs
./bin/cryptofs initmkdir -p testdir
echo "hello from cryptofs" > testdir/hello.txt
echo "another file" > testdir/notes.txt
# Low-risk: agent can view and list only
./bin/cryptofs index --root ./testdir --tag myfiles --risk low --recursive
# Verify
./bin/cryptofs list --tag myfilesYou should see hello.txt and notes.txt each with an oid.
# Copy the plugin directory contents into openclaw's extensions folder
mkdir -p ~/.openclaw/extensions/cryptofs
cp openclaw-plugin/cryptofs/* ~/.openclaw/extensions/cryptofs/Set environment variables so the gateway process can find the binary and Python interpreter.
These must be set via systemctl so the gateway service inherits them:
systemctl --user set-environment \
CRYPTOFS_BINARY=/absolute/path/to/gatekeeper/bin/cryptofs
# Only needed if your system python3 is older than 3.7
systemctl --user set-environment \
CRYPTOFS_PYTHON=/path/to/python3.10Verify the files are in place:
ls ~/.openclaw/extensions/cryptofs/
# Should show: index.ts openclaw.plugin.jsonAdd the plugin and disable raw exec access:
cat ~/.openclaw/openclaw.json | python3 -c "
import json, sys
cfg = json.load(sys.stdin)
p = cfg.setdefault('plugins', {})
p['allow'] = ['cryptofs']
t = cfg.setdefault('tools', {})
t['deny'] = ['group:web', 'browser', 'exec']
t.pop('exec', None)
print(json.dumps(cfg, indent=2))
" > /tmp/openclaw.json && mv /tmp/openclaw.json ~/.openclaw/openclaw.jsonVerify:
cat ~/.openclaw/openclaw.json | python3 -m json.tool | grep -A8 '"plugins"'
# Should show: "allow": ["cryptofs"]
cat ~/.openclaw/openclaw.json | python3 -m json.tool | grep -A5 '"tools"'
# Should show: "deny": ["group:web", "browser", "exec"]The exec deny is critical as it removes the agent's ability to run arbitrary
shell commands, making cryptofs the only way the agent can touch the filesystem.
The workspace/AGENTS.md included in this repo already has the cryptofs tool
registration. If you are using this repo's workspace directory, just confirm it is there:
tail -12 workspace/AGENTS.md
# Should show the cryptofs Tools sectionopenclaw gateway restart
sleep 3openclaw agent --agent main -m "Use cryptofs_list to list all files with tag myfiles"Expected: agent calls cryptofs_list and returns a list of oids with labels.
openclaw agent --agent main -m "Use cryptofs_view to read the contents of hello.txt. First use cryptofs_list to get the oid."Expected: agent calls cryptofs_list then cryptofs_view, returns the file content.
openclaw agent --agent main -m "Run bash command: ls /tmp"Expected: agent reports it has no exec access and cannot run the command.
Re-index as high-risk to enable delete:
./bin/cryptofs index --root ./testdir --tag myfiles --risk high --recursiveFind the oid of hello.txt:
./bin/cryptofs list --tag myfiles
# Note the oid for hello.txt with risk=highHuman issues the delete request and approval:
CLAW=./bin/cryptofs
OID=<oid of hello.txt with risk=high>
# Issue request
RID=$($CLAW request --action delete --oid "$OID" --session demo --reason "cleanup" \
| python3 -c "import json,sys; print(json.load(sys.stdin)['request_id'])")
echo "Request ID: $RID"
# Approve (human confirms)
$CLAW approve --request-id "$RID" --approver humanThen let the agent execute the approved delete:
openclaw agent --agent main -m "Use cryptofs_exec_delete to execute the approved delete. request_id is $RID"Expected: agent calls cryptofs_exec_delete, file is deleted. Replay of the
same token fails with token already used.
Verify:
ls testdir/
# hello.txt is gone, notes.txt remains| Property | Detail |
|---|---|
| Path blindness | Agent sees only oid references, never real paths or filenames |
| No bash access | exec tool disabled; agent cannot run shell commands |
| Token single-use | Each token has a unique nonce; replay is rejected |
| Token expiry | TTL enforced (default 120s, max 86400s) |
| Action binding | A view token cannot execute a list or delete |
| Object binding | Token is bound to a specific inode; file replacement is detected |
| Delete requires approval | Human must run approve before a delete token can be minted |
| Approval single-use | Each approval produces exactly one token |
| Audit log | Every exec, approve, and mint-approved is recorded in SQLite |
cryptofs is a plain CLI that outputs JSON. The openclaw plugin is one example
integration.
| Framework | How |
|---|---|
| openclaw | Use openclaw-plugin/cryptofs/ (included) |
| MCP | Wrap each subcommand as an MCP tool, return JSON output |
| LangChain | Wrap each subcommand as a Tool object |
| Custom | subprocess.run(["bin/cryptofs", ...]) and parse JSON |
The security logic lives entirely in bin/cryptofs. The framework wrapper is
just glue as it forwards arguments and parses JSON. No security logic belongs
in the wrapper.
bin/cryptofs The tool itself (standalone CLI)
openclaw-plugin/
cryptofs/
index.ts openclaw plugin to wrap cryptofs as agent tools
openclaw.plugin.json plugin manifest
README.md plugin install guide
workspace/
AGENTS.md agent workspace to register cryptofs here
skills/cryptofs/
SKILL.md runtime command reference for the agent
INTEGRATION.md step-by-step setup guide
demo.sh end-to-end demo script
test_expiry.sh token expiry smoke test
| Error | Cause | Fix |
|---|---|---|
active object not found |
oid deleted or never indexed | Re-run list to get a fresh oid |
token already used |
Nonce replay | Mint a new token |
token expired |
TTL elapsed | Mint a new token |
object binding mismatch |
File replaced/moved since indexing | Re-index |
request is not approved: minted |
mint-approved called twice |
Not allowed; re-request |
target object is no longer active; cannot approve |
Object deleted before approval | Re-index and re-request |
object has risk='low' |
Tried to delete a low-risk object | Re-index with --risk high |
If you use GateKeeper in a paper, report, thesis, or study, please cite this repository:
@misc{Chen2026GateKeeper,
author = {Yuyan Chen},
title = {GateKeeper: A Cryptographic File Gate for AI Agents},
year = {2026},
url = {https://github.com/Yukyin/gatekeeper}
}Noncommercial use is governed by LICENSE (PolyForm Noncommercial 1.0.0).
Commercial use requires a separate agreement COMMERCIAL_LICENSE.md.
📨 Commercial inquiries: yolandachen0313@gmail.com