47 Commits

Author SHA1 Message Date
Dylan Conway
7a725a314f Remove lodash-es dependency (#206)
* Remove lodash-es dependency

Replace the single cloneDeep() call with native structuredClone()
(available in Node >=17; project requires >=18). Drops lodash-es
and @types/lodash-es from dependencies.

* Bump version to 0.0.49
2026-04-02 18:58:36 -07:00
Dylan Conway
bc3f0faa98 Bump to 0.0.48 and fix npm audit vulnerabilities (#205)
- Bump lodash-es to ^4.18.1 (fixes GHSA-r5fr-rjxr-66jc, GHSA-f23m-r3pf-42rh)
- Update transitive deps via npm audit fix: ajv, brace-expansion, flatted,
  minimatch, picomatch, yaml
- Bump package version to 0.0.48
2026-04-02 18:38:11 -07:00
Dylan Conway
ed5a909983 Fix enableWeakerNestedSandbox after apply-seccomp namespace changes (#196)
* Fix enableWeakerNestedSandbox after apply-seccomp namespace changes

apply-seccomp now creates a nested userns and writes /proc/self/setgroups
and uid_map before applying the seccomp filter. That broke
enableWeakerNestedSandbox in two ways:

  1. Without --proc, bwrap's --ro-bind / / leaves /proc read-only.
     apply-seccomp's setgroups write dies with EROFS.

  2. In unprivileged Docker (the flag's target), apply-seccomp's proc
     remount fails the kernel domination check — Docker's /proc masks
     are MNT_LOCKED in the less-privileged nested userns.

And the reason bwrap never got that far in Docker: bwrap only auto-adds
--unshare-user when EUID != 0. Docker's default is EUID=0 without
CAP_SYS_ADMIN; bwrap assumes it has caps, tries direct clone(NEWPID),
and EPERMs before apply-seccomp runs.

Changes:

  - bwrap args for weak mode: --unshare-user (force userns even as
    EUID=0) and --bind /proc /proc (restore rw /proc for setgroups)
  - apply-seccomp: tolerate mount(/proc) EPERM. The nested userns is
    the isolation boundary; the proc remount only hides outer PIDs
    from `ls /proc`.

Fixes the two failing mandatory-deny-paths tests that exercise
enableWeakerNestedSandbox. No test changes required.

Bump version to 0.0.46.

* Run mandatory-deny-paths tests in CI

These exercise enableWeakerNestedSandbox — the two tests that broke
when apply-seccomp started nesting namespaces. Add explicitly until
the full-suite CI change lands.

* Remove CI step comment
2026-03-31 12:56:06 -07:00
David Dworken
18f2668b44 Defer bwrap mount point cleanup until concurrent sandboxes finish (#184)
* Isolate seccomp workload in nested PID namespace and block io_uring

apply-seccomp now creates a nested user+PID+mount namespace before applying
the seccomp filter. The user command runs as PID 2 under a non-dumpable PID 1
reaper, with /proc remounted so only the inner process tree is visible. This
prevents the sandboxed command from ptracing or patching the unfiltered bwrap
init, bash wrapper, or socat helpers via /proc/N/mem, regardless of the host's
kernel.yama.ptrace_scope setting. Namespace setup failure aborts rather than
silently degrading.

The BPF filter now also blocks io_uring_setup/enter/register. IORING_OP_SOCKET
(Linux 5.19+) creates sockets without going through socket(), and seccomp
cannot inspect SQEs in the shared ring, so denying ring creation entirely is
the only safe option.

The filter generator now accepts an optional target-arch argument so a single
builder can emit both x64 and arm64 filters. Prebuilt binaries and filters are
regenerated for both architectures.

* Pass CAP_SYS_ADMIN to apply-seccomp and clear ambient caps before exec

apply-seccomp needs CAP_SYS_ADMIN to unshare PID+mount namespaces. The
original approach obtained it via unshare(CLONE_NEWUSER), but on hosts
where an LSM restricts unprivileged user namespaces (Ubuntu 24.04 with
AppArmor defaults), the nested userns is created without capabilities
and the setgroups write fails.

bwrap now passes --cap-add CAP_SYS_ADMIN (scoped to its user namespace)
so apply-seccomp can unshare directly. The nested-userns path remains as
a fallback for standalone invocation.

apply-seccomp clears the ambient capability set after remounting /proc,
so the sandboxed command's execve drops to zero capabilities and cannot
umount /proc to reveal the outer mount underneath. Two new tests cover
CapEff=0 and umount denial.

* chore: bump version to 0.0.44

* Add --unshare-user so --cap-add works with setuid bwrap

Setuid bwrap rejects --cap-add from non-root because it would grant
real host capabilities. --unshare-user forces user-namespace mode so
the capability is scoped to that namespace and the flag is accepted.

* Disable AppArmor userns restriction in CI instead of using setuid bwrap

Setuid bwrap rejects --cap-add from non-root, so that path is a dead end.
Instead, disable kernel.apparmor_restrict_unprivileged_userns in CI so
apply-seccomp's nested-userns path works without any bwrap cooperation.
This matches what production Ubuntu 24.04 users need to do anyway, now
documented in the README.

* Exit inner init as soon as the worker exits

reap_until was waiting for all children including orphaned background
processes reparented to PID 1, which hung the sandbox when the user
command backgrounded something long-running and then exited. Return
immediately when the worker terminates; PID 1 exiting tears down the
namespace and SIGKILLs any stragglers.

* Defer bwrap mount point cleanup until all concurrent sandboxes finish

When two sandboxed commands run concurrently and one finishes first,
cleanupBwrapMountPoints() was deleting mount point files that the
still-running sandbox still depended on. Deleting the mountpoint's
dentry on the host detaches the bind mount in the child namespace
(the dentry is unhashed, so path lookup no longer finds the mount),
so the deny rule stops applying inside the still-running sandbox.

Add an active-sandbox counter: wrapCommandWithSandboxLinux()
increments it, cleanupBwrapMountPoints() decrements it and defers
file deletion until the counter reaches zero. A {force: true} option
bypasses the counter for process-exit and reset().

Also bumps version to 0.0.45.

---------

Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2026-03-30 17:18:35 -07:00
Alice T'Poteat
732a12a4c2 chore: bump version to 0.0.44 (#192) 2026-03-30 16:12:22 -07:00
David Dworken
62e61c0e74 Sandbox hardening: TMPDIR write scope and seccomp arg comparison (#182)
* Harden macOS sandbox to only use the configured TMPDIR for writes

* Use 32-bit masked comparison for socket() domain argument in seccomp filter
2026-03-23 17:41:10 -07:00
Alice T'Poteat
20f5176a94 chore: bump version to 0.0.42 (#169) 2026-03-12 16:12:06 -07:00
David Dworken
b3716c6d01 fix: set GIT_SSH_COMMAND on Linux so git over SSH resolves DNS via proxy (#168)
* fix: set GIT_SSH_COMMAND on Linux so git over SSH resolves DNS via proxy

On Linux, the sandbox runs inside an isolated network namespace
(--unshare-net) with no DNS. Previously GIT_SSH_COMMAND was only set
on macOS (using BSD nc), so git push/fetch over SSH on Linux failed with
"Could not resolve hostname".

Use socat's PROXY: address type (HTTP CONNECT) against the HTTP proxy
bridge on port 3128. socat is already a required Linux dependency, and
PROXY: works on all socat versions (unlike SOCKS5-CONNECT which needs
>= 1.8.0).

Also bump version to 0.0.41 (and sync package-lock.json which had
drifted to 0.0.39).

Fixes #161

* test: add integration tests for git over SSH through sandbox proxy

Adds two tests covering the GIT_SSH_COMMAND fix for #161:

1. Verifies GIT_SSH_COMMAND is set inside the Linux sandbox and routes
   through socat PROXY (HTTP CONNECT).

2. Runs git ls-remote over SSH against github.com and asserts DNS
   resolution succeeds. Uses /dev/null as the SSH identity so the
   expected outcome is 'Permission denied (publickey)' -- reaching
   that error proves TCP connect + SSH handshake worked, while
   'Could not resolve hostname' would indicate regression.
2026-03-12 11:32:27 -07:00
David Dworken
5ec63cb862 Bump version to 0.0.39 2026-02-25 17:09:02 -08:00
David Dworken
9f59523e12 security: warn and skip symlink write paths pointing outside boundaries (#138)
* security: warn and skip symlink write paths pointing outside boundaries

bwrap follows symlinks when doing bind mounts, so if a user configures
an allowWrite path that is a symlink pointing to an unexpected location,
that target location would become writable.

For example, if ./src is a symlink to /etc, configuring allowWrite: ['./src']
would make /etc writable through the symlink.

This change:
- Detects when a write path is a symlink pointing outside expected boundaries
- Prints a warning to inform the user
- Skips the path instead of making the unexpected target writable

Fixes potential symlink-based sandbox escape in write path configuration.

* test: add unit and integration tests for symlink write path detection, bump to 0.0.38

* fix: trim trailing slashes before symlink comparison in write path check

realpathSync never returns trailing slashes, but normalizedPath may have
one, causing a false mismatch that incorrectly treats the path as a
symlink and skips it. Strip trailing slashes before comparing.

Add test to reproduce the trailing slash issue.

---------

Co-authored-by: ollie-anthropic <ollie@anthropic.com>
2026-02-18 17:40:44 -08:00
David Dworken
8235d55339 chore: bump version to 0.0.37 2026-02-08 20:39:05 -08:00
David Dworken
0dc4322cda Re-introduce non-existent deny path protection with mount point cleanup
PR #80 hardened the sandbox by mounting /dev/null over non-existent deny
paths to prevent their creation, but this caused bwrap to leave empty
"ghost dotfiles" on the host (issue #85), which PR #91 reverted. This
re-introduces the protection with proper cleanup: mount points are
tracked and removed via cleanupBwrapMountPoints(). A new lightweight
cleanupAfterCommand() API is exposed on SandboxManager for callers to
invoke after each command, and the srt CLI calls it on child exit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 19:21:15 -08:00
David Dworken
fd054fc27a Expand denyRead glob patterns to concrete paths on Linux 2026-02-03 09:28:27 -08:00
ollie-anthropic
f5ba41a3d1 chore: upgrade deps and bump to 0.0.34 (#112)
* chore: upgrade lodash-es to 4.17.23 and fix js-yaml vuln

- Upgrade lodash-es from 4.17.21 to 4.17.23
- Fix js-yaml prototype pollution vulnerability (GHSA-mh29-5h37-fv8m)

npm audit now shows 0 vulnerabilities.

* chore: bump version to 0.0.34
2026-02-02 16:32:08 -08:00
David Dworken
bf36e4406c Harden sandbox by removing unnecessary trustd.agent mach-lookup (#108)
* Harden sandbox by removing unnecessary trustd.agent mach-lookup

* Bump version in package-lock.json
2026-02-02 02:22:00 -08:00
ollie-anthropic
37cd88c011 update pointers 2026-01-23 15:19:17 -08:00
ollie-anthropic
9c9bd59160 chore: bump version to 0.0.29 2026-01-20 22:47:30 -08:00
ollie-anthropic
6eb213b33e update pointers 2026-01-14 19:21:03 -08:00
ollie-anthropic
d4761dc924 chore: bump version to 0.0.27 2026-01-14 18:42:21 -08:00
Samuel Attard
426a960b36 feat: add mitm proxy configuration options 2026-01-14 14:12:52 -08:00
Jacques Paye
7ddf03cc12 switch to CLAUDE_TMPDIR 2026-01-08 12:03:54 -08:00
ollie-anthropic
0ebff52ac5 update pointers 2026-01-07 20:51:32 +00:00
David Dworken
43d549eee9 Harden sandbox deny path handling for non-existent files
Previously, non-existent paths in the deny list were skipped since
bwrap cannot ro-bind a file that doesn't exist. This change adds
defense-in-depth by mounting /dev/null at the first non-existent
path component, which prevents creation of the denied path.

- Add findFirstNonExistentComponent helper to locate mount point
- Mount /dev/null at first missing component to block path creation
- Add tests for non-existent deny path protection

Bump version to 0.0.24

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-06 14:31:22 -08:00
ollie-anthropic
87872e4dfd upgrade package lock 2025-12-18 15:12:54 +00:00
ollie-anthropic
e6404b64ec Bump version to 0.0.22
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-15 16:09:06 +00:00
Kyle Gao
d96a5769af Bump version to 0.0.21
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 11:38:10 -05:00
David Dworken
22e4efab3b Bump version to 0.0.20
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 19:13:38 +00:00
David Dworken
826ed320b4 Add --new-session and --die-with-parent flags to bubblewrap
Security improvements:
- --new-session: Protects against CVE-2017-5226 (TIOCSTI terminal injection)
  by calling setsid() to disconnect from the controlling terminal
- --die-with-parent: Ensures all sandbox processes are killed (via SIGKILL)
  when bwrap's parent dies, preventing orphan processes

Both flags are used by Flatpak in production and work correctly with our
existing --unshare-pid flag (required for --die-with-parent to kill all
descendant processes).

Added regression tests to verify:
- Child processes are killed when sandbox is terminated via timeout
- No orphan processes remain after forced termination

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 17:46:29 +00:00
JB
98df7dc1b2 Bumping version to 0.0.19 2025-12-04 15:30:58 -05:00
ollie-anthropic
efeeb18599 update pointers 2025-11-24 16:31:46 -08:00
ollie-anthropic
7c43068f3c update package json 2025-11-18 16:29:06 -08:00
ollie-anthropic
004536f6b7 update package.json 2025-11-17 21:29:36 -08:00
ollie-anthropic
2aec2a7949 Improve the flexibility of the API and include better defaults 2025-11-16 22:31:40 -08:00
ollie-anthropic
943a2e8e15 Add bun types to dev dependencies 2025-11-16 19:11:21 -08:00
ollie-anthropic
7754a76895 seccomp fail gracefully 2025-11-16 16:14:59 -08:00
ollie-anthropic
c43b907285 fix path finding 2025-11-14 02:31:05 -08:00
ollie-anthropic
8f62627003 update pointers 2025-11-13 14:49:37 -08:00
ollie-anthropic
dd87f510c4 Merge pull request #31 from anthropic-experimental/ollie/add-config-mutation-and-bump-pointers
Add config mutation and bump pointers
2025-11-13 13:26:02 -08:00
ollie-anthropic
398ba58ce3 add config mutation and bump pointers 2025-11-10 00:14:08 -08:00
jalateras
fa165d8553 Add pre-commit hooks for code quality enforcement
- Install husky v9.1.7 for git hook management
- Install lint-staged v16.2.6 for efficient staged file checking
- Configure pre-commit hook to run ESLint and Prettier on staged TypeScript files
- Add prepare script to ensure hooks are installed after npm install

This setup automatically enforces code quality standards before each commit,
running linting and formatting only on staged files for optimal performance.
2025-11-06 16:22:23 +11:00
ollie-anthropic
fff6ad632e Improve dependency checking and error messages
- Add early dependency validation in initialize() before starting any services
- Provide platform-specific error messages listing required dependencies
  - Linux: ripgrep (rg), bubblewrap (bwrap), and socat
  - macOS: ripgrep (rg)
- Refactor checkDependencies() for cleaner code structure
- Bump version to 0.0.7

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 18:34:50 -08:00
ollie-anthropic
8cc0e68506 update pointers 2025-11-04 16:36:01 -08:00
ollie-anthropic
c8a64e944f 004-pointers 2025-11-03 19:30:13 -08:00
ollie-anthropic
135c63b4bb 0.0.3 2025-10-31 17:18:39 -07:00
ollie-anthropic
828cc03210 Update package lock to 0.0.2 2025-10-30 16:24:24 -07:00
ollie-anthropic
c7118a914c Update README and rename settings file to srt-settings.json 2025-10-23 20:40:55 -07:00
ollie-anthropic
b483c6113b Initial release 2025-10-20 10:19:42 -07:00