@voratiq/sandbox-runtime 0.0.29-voratiq0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/LICENSE +201 -0
- package/NOTICE +12 -0
- package/README.md +17 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +158 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/sandbox/generate-seccomp-filter.d.ts +65 -0
- package/dist/sandbox/generate-seccomp-filter.d.ts.map +1 -0
- package/dist/sandbox/generate-seccomp-filter.js +185 -0
- package/dist/sandbox/generate-seccomp-filter.js.map +1 -0
- package/dist/sandbox/http-proxy.d.ts +14 -0
- package/dist/sandbox/http-proxy.d.ts.map +1 -0
- package/dist/sandbox/http-proxy.js +238 -0
- package/dist/sandbox/http-proxy.js.map +1 -0
- package/dist/sandbox/linux-sandbox-utils.d.ts +121 -0
- package/dist/sandbox/linux-sandbox-utils.d.ts.map +1 -0
- package/dist/sandbox/linux-sandbox-utils.js +723 -0
- package/dist/sandbox/linux-sandbox-utils.js.map +1 -0
- package/dist/sandbox/macos-sandbox-utils.d.ts +57 -0
- package/dist/sandbox/macos-sandbox-utils.d.ts.map +1 -0
- package/dist/sandbox/macos-sandbox-utils.js +611 -0
- package/dist/sandbox/macos-sandbox-utils.js.map +1 -0
- package/dist/sandbox/observability.d.ts +56 -0
- package/dist/sandbox/observability.d.ts.map +1 -0
- package/dist/sandbox/observability.js +140 -0
- package/dist/sandbox/observability.js.map +1 -0
- package/dist/sandbox/sandbox-config.d.ts +277 -0
- package/dist/sandbox/sandbox-config.d.ts.map +1 -0
- package/dist/sandbox/sandbox-config.js +166 -0
- package/dist/sandbox/sandbox-config.js.map +1 -0
- package/dist/sandbox/sandbox-manager.d.ts +50 -0
- package/dist/sandbox/sandbox-manager.d.ts.map +1 -0
- package/dist/sandbox/sandbox-manager.js +816 -0
- package/dist/sandbox/sandbox-manager.js.map +1 -0
- package/dist/sandbox/sandbox-schemas.d.ts +53 -0
- package/dist/sandbox/sandbox-schemas.d.ts.map +1 -0
- package/dist/sandbox/sandbox-schemas.js +3 -0
- package/dist/sandbox/sandbox-schemas.js.map +1 -0
- package/dist/sandbox/sandbox-utils.d.ts +83 -0
- package/dist/sandbox/sandbox-utils.d.ts.map +1 -0
- package/dist/sandbox/sandbox-utils.js +343 -0
- package/dist/sandbox/sandbox-utils.js.map +1 -0
- package/dist/sandbox/sandbox-violation-store.d.ts +19 -0
- package/dist/sandbox/sandbox-violation-store.d.ts.map +1 -0
- package/dist/sandbox/sandbox-violation-store.js +54 -0
- package/dist/sandbox/sandbox-violation-store.js.map +1 -0
- package/dist/sandbox/socks-proxy.d.ts +14 -0
- package/dist/sandbox/socks-proxy.d.ts.map +1 -0
- package/dist/sandbox/socks-proxy.js +109 -0
- package/dist/sandbox/socks-proxy.js.map +1 -0
- package/dist/utils/config-loader.d.ts +11 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +60 -0
- package/dist/utils/config-loader.js.map +1 -0
- package/dist/utils/debug.d.ts +7 -0
- package/dist/utils/debug.d.ts.map +1 -0
- package/dist/utils/debug.js +25 -0
- package/dist/utils/debug.js.map +1 -0
- package/dist/utils/platform.d.ts +15 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +49 -0
- package/dist/utils/platform.js.map +1 -0
- package/dist/utils/ripgrep.d.ts +20 -0
- package/dist/utils/ripgrep.d.ts.map +1 -0
- package/dist/utils/ripgrep.js +51 -0
- package/dist/utils/ripgrep.js.map +1 -0
- package/dist/vendor/seccomp/arm64/apply-seccomp +0 -0
- package/dist/vendor/seccomp/arm64/unix-block.bpf +0 -0
- package/dist/vendor/seccomp/x64/apply-seccomp +0 -0
- package/dist/vendor/seccomp/x64/unix-block.bpf +0 -0
- package/dist/vendor/seccomp-src/apply-seccomp.c +98 -0
- package/dist/vendor/seccomp-src/seccomp-unix-block.c +97 -0
- package/package.json +90 -0
- package/vendor/seccomp/arm64/apply-seccomp +0 -0
- package/vendor/seccomp/arm64/unix-block.bpf +0 -0
- package/vendor/seccomp/x64/apply-seccomp +0 -0
- package/vendor/seccomp/x64/unix-block.bpf +0 -0
- package/vendor/seccomp-src/apply-seccomp.c +98 -0
- package/vendor/seccomp-src/seccomp-unix-block.c +97 -0
package/package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@voratiq/sandbox-runtime",
|
|
3
|
+
"version": "0.0.29-voratiq0",
|
|
4
|
+
"description": "(Voratiq-maintained fork of the) Anthropic Sandbox Runtime (ASRT) - A general-purpose tool for wrapping security boundaries around arbitrary processes",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"srt": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=18.0.0"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"postbuild": "[ -d vendor ] && cp -r vendor dist/ || true",
|
|
17
|
+
"build:seccomp": "scripts/build-seccomp-binaries.sh",
|
|
18
|
+
"clean": "rm -rf dist",
|
|
19
|
+
"test": "bun test",
|
|
20
|
+
"test:unit": "bun test test/config-validation.test.ts test/sandbox/seccomp-filter.test.ts",
|
|
21
|
+
"test:integration": "bun test test/sandbox/integration.test.ts",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"lint": "eslint 'src/**/*.ts' --fix --cache --cache-location=node_modules/.cache/.eslintcache",
|
|
24
|
+
"lint:check": "eslint 'src/**/*.ts' --cache --cache-location=node_modules/.cache/.eslintcache",
|
|
25
|
+
"format": "prettier --write 'src/**/*.ts' --cache --log-level warn",
|
|
26
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
27
|
+
"prepare": "husky"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@pondwader/socks5-server": "^1.0.10",
|
|
31
|
+
"@types/lodash-es": "^4.17.12",
|
|
32
|
+
"commander": "^12.1.0",
|
|
33
|
+
"lodash-es": "^4.17.21",
|
|
34
|
+
"shell-quote": "^1.8.3",
|
|
35
|
+
"zod": "^3.24.1"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@eslint/js": "^9.14.0",
|
|
39
|
+
"@types/bun": "^1.3.2",
|
|
40
|
+
"@types/node": "^18",
|
|
41
|
+
"@types/shell-quote": "^1.7.5",
|
|
42
|
+
"eslint": "^9.14.0",
|
|
43
|
+
"eslint-config-prettier": "^8.10.0",
|
|
44
|
+
"eslint-import-resolver-typescript": "^3.6.3",
|
|
45
|
+
"eslint-plugin-import": "^2.31.0",
|
|
46
|
+
"eslint-plugin-n": "^17.16.2",
|
|
47
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
48
|
+
"globals": "^15.12.0",
|
|
49
|
+
"husky": "^9.1.7",
|
|
50
|
+
"lint-staged": "^16.2.6",
|
|
51
|
+
"prettier": "3.3.3",
|
|
52
|
+
"typescript": "^5.6.3",
|
|
53
|
+
"typescript-eslint": "^8.13.0"
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"dist",
|
|
57
|
+
"vendor",
|
|
58
|
+
"CHANGELOG.md",
|
|
59
|
+
"README.md",
|
|
60
|
+
"LICENSE",
|
|
61
|
+
"NOTICE"
|
|
62
|
+
],
|
|
63
|
+
"keywords": [
|
|
64
|
+
"sandbox",
|
|
65
|
+
"seatbelt",
|
|
66
|
+
"sandbox-exec",
|
|
67
|
+
"anthropic",
|
|
68
|
+
"claude",
|
|
69
|
+
"security",
|
|
70
|
+
"bubblewrap",
|
|
71
|
+
"network-filtering",
|
|
72
|
+
"filesystem-restrictions"
|
|
73
|
+
],
|
|
74
|
+
"author": "Voratiq",
|
|
75
|
+
"license": "Apache-2.0",
|
|
76
|
+
"repository": {
|
|
77
|
+
"type": "git",
|
|
78
|
+
"url": "git+https://github.com/voratiq/sandbox-runtime.git"
|
|
79
|
+
},
|
|
80
|
+
"bugs": {
|
|
81
|
+
"url": "https://github.com/voratiq/sandbox-runtime/issues"
|
|
82
|
+
},
|
|
83
|
+
"homepage": "https://github.com/voratiq/sandbox-runtime#readme",
|
|
84
|
+
"lint-staged": {
|
|
85
|
+
"*.ts": [
|
|
86
|
+
"eslint --fix --cache --cache-location=node_modules/.cache/.eslintcache",
|
|
87
|
+
"prettier --write"
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* apply-seccomp.c - Apply seccomp BPF filter and exec command
|
|
3
|
+
*
|
|
4
|
+
* Usage: apply-seccomp <filter.bpf> <command> [args...]
|
|
5
|
+
*
|
|
6
|
+
* This program reads a pre-compiled BPF filter from a file, applies it
|
|
7
|
+
* using prctl(PR_SET_SECCOMP), and then execs the specified command.
|
|
8
|
+
*
|
|
9
|
+
* The BPF filter must be in the format expected by SECCOMP_MODE_FILTER:
|
|
10
|
+
* - struct sock_fprog { unsigned short len; struct sock_filter *filter; }
|
|
11
|
+
* - Each filter instruction is 8 bytes (BPF instruction format)
|
|
12
|
+
*
|
|
13
|
+
* Compile: gcc -static -O2 -o apply-seccomp apply-seccomp.c
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#include <stdio.h>
|
|
17
|
+
#include <stdlib.h>
|
|
18
|
+
#include <string.h>
|
|
19
|
+
#include <unistd.h>
|
|
20
|
+
#include <fcntl.h>
|
|
21
|
+
#include <sys/prctl.h>
|
|
22
|
+
#include <linux/seccomp.h>
|
|
23
|
+
#include <linux/filter.h>
|
|
24
|
+
#include <errno.h>
|
|
25
|
+
|
|
26
|
+
#ifndef PR_SET_NO_NEW_PRIVS
|
|
27
|
+
#define PR_SET_NO_NEW_PRIVS 38
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
#ifndef SECCOMP_MODE_FILTER
|
|
31
|
+
#define SECCOMP_MODE_FILTER 2
|
|
32
|
+
#endif
|
|
33
|
+
|
|
34
|
+
#define MAX_FILTER_SIZE 4096 // Maximum BPF filter size in bytes
|
|
35
|
+
|
|
36
|
+
int main(int argc, char *argv[], char *envp[]) {
|
|
37
|
+
if (argc < 3) {
|
|
38
|
+
fprintf(stderr, "Usage: %s <filter.bpf> <command> [args...]\n", argv[0]);
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const char *filter_path = argv[1];
|
|
43
|
+
char **command_argv = &argv[2];
|
|
44
|
+
|
|
45
|
+
// Open and read BPF filter file
|
|
46
|
+
int fd = open(filter_path, O_RDONLY);
|
|
47
|
+
if (fd < 0) {
|
|
48
|
+
perror("Failed to open BPF filter file");
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Read filter into memory
|
|
53
|
+
unsigned char filter_bytes[MAX_FILTER_SIZE];
|
|
54
|
+
ssize_t filter_size = read(fd, filter_bytes, MAX_FILTER_SIZE);
|
|
55
|
+
close(fd);
|
|
56
|
+
|
|
57
|
+
if (filter_size < 0) {
|
|
58
|
+
perror("Failed to read BPF filter");
|
|
59
|
+
return 1;
|
|
60
|
+
}
|
|
61
|
+
if (filter_size == 0) {
|
|
62
|
+
fprintf(stderr, "BPF filter file is empty\n");
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
if (filter_size % 8 != 0) {
|
|
66
|
+
fprintf(stderr, "Invalid BPF filter size: %zd (must be multiple of 8)\n", filter_size);
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Convert bytes to sock_filter instructions
|
|
71
|
+
unsigned short filter_len = filter_size / 8;
|
|
72
|
+
struct sock_filter *filter = (struct sock_filter *)filter_bytes;
|
|
73
|
+
|
|
74
|
+
// Set up sock_fprog structure
|
|
75
|
+
struct sock_fprog prog = {
|
|
76
|
+
.len = filter_len,
|
|
77
|
+
.filter = filter,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Set NO_NEW_PRIVS to allow seccomp without CAP_SYS_ADMIN
|
|
81
|
+
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
|
|
82
|
+
perror("prctl(PR_SET_NO_NEW_PRIVS) failed");
|
|
83
|
+
return 1;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Apply seccomp filter
|
|
87
|
+
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) != 0) {
|
|
88
|
+
perror("prctl(PR_SET_SECCOMP) failed");
|
|
89
|
+
return 1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Exec the command with seccomp filter active
|
|
93
|
+
execvp(command_argv[0], command_argv);
|
|
94
|
+
|
|
95
|
+
// If we get here, exec failed
|
|
96
|
+
perror("execvp failed");
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Seccomp BPF filter generator to block Unix domain socket creation
|
|
3
|
+
*
|
|
4
|
+
* This program generates a seccomp-bpf filter that blocks the socket() syscall
|
|
5
|
+
* when called with AF_UNIX as the domain argument. This prevents creation of
|
|
6
|
+
* Unix domain sockets while allowing all other socket types (AF_INET, AF_INET6, etc.)
|
|
7
|
+
* and all other syscalls.
|
|
8
|
+
*
|
|
9
|
+
* The filter is exported in a format compatible with bubblewrap's --seccomp flag.
|
|
10
|
+
*
|
|
11
|
+
* SECURITY LIMITATION - 32-bit x86 (ia32):
|
|
12
|
+
* TODO: This filter does NOT block socketcall() syscall, which is a security issue
|
|
13
|
+
* on 32-bit x86 systems. On ia32, the socket() syscall doesn't exist - instead,
|
|
14
|
+
* all socket operations are multiplexed through socketcall():
|
|
15
|
+
* - socketcall(SYS_SOCKET, [AF_UNIX, ...]) - can bypass this filter
|
|
16
|
+
* - socketcall(SYS_SOCKETPAIR, [AF_UNIX, ...]) - can bypass this filter
|
|
17
|
+
*
|
|
18
|
+
* To fix this, we need to add conditional rules that:
|
|
19
|
+
* 1. Check if socketcall() exists on the current architecture (32-bit x86 only)
|
|
20
|
+
* 2. Block socketcall(SYS_SOCKET, ...) when first arg of sub-call is AF_UNIX
|
|
21
|
+
* 3. Block socketcall(SYS_SOCKETPAIR, ...) when first arg of sub-call is AF_UNIX
|
|
22
|
+
*
|
|
23
|
+
* This requires inspecting the arguments passed to socketcall, which is more
|
|
24
|
+
* complex BPF logic. For now, 32-bit x86 is not supported.
|
|
25
|
+
*
|
|
26
|
+
* Compilation:
|
|
27
|
+
* gcc -o seccomp-unix-block seccomp-unix-block.c -lseccomp
|
|
28
|
+
*
|
|
29
|
+
* Usage:
|
|
30
|
+
* ./seccomp-unix-block <output-file>
|
|
31
|
+
*
|
|
32
|
+
* Dependencies:
|
|
33
|
+
* - libseccomp (libseccomp-dev package on Debian/Ubuntu)
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
#include <errno.h>
|
|
37
|
+
#include <fcntl.h>
|
|
38
|
+
#include <stdio.h>
|
|
39
|
+
#include <stdlib.h>
|
|
40
|
+
#include <string.h>
|
|
41
|
+
#include <unistd.h>
|
|
42
|
+
#include <seccomp.h>
|
|
43
|
+
#include <sys/socket.h>
|
|
44
|
+
#include <sys/stat.h>
|
|
45
|
+
#include <sys/types.h>
|
|
46
|
+
|
|
47
|
+
int main(int argc, char *argv[]) {
|
|
48
|
+
scmp_filter_ctx ctx;
|
|
49
|
+
int rc;
|
|
50
|
+
|
|
51
|
+
if (argc != 2) {
|
|
52
|
+
fprintf(stderr, "Usage: %s <output-file>\n", argv[0]);
|
|
53
|
+
return 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const char *output_file = argv[1];
|
|
57
|
+
|
|
58
|
+
/* Create seccomp context with default action ALLOW */
|
|
59
|
+
ctx = seccomp_init(SCMP_ACT_ALLOW);
|
|
60
|
+
if (ctx == NULL) {
|
|
61
|
+
fprintf(stderr, "Error: Failed to initialize seccomp context\n");
|
|
62
|
+
return 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Add rule to block socket(AF_UNIX, ...) */
|
|
66
|
+
/* socket() syscall signature: int socket(int domain, int type, int protocol) */
|
|
67
|
+
/* arg0 = domain (AF_UNIX = 1) */
|
|
68
|
+
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(socket), 1,
|
|
69
|
+
SCMP_A0(SCMP_CMP_EQ, AF_UNIX));
|
|
70
|
+
if (rc < 0) {
|
|
71
|
+
fprintf(stderr, "Error: Failed to add seccomp rule: %s\n", strerror(-rc));
|
|
72
|
+
seccomp_release(ctx);
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Export the filter to a file */
|
|
77
|
+
int fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
|
78
|
+
if (fd < 0) {
|
|
79
|
+
fprintf(stderr, "Error: Failed to open output file: %s\n", strerror(errno));
|
|
80
|
+
seccomp_release(ctx);
|
|
81
|
+
return 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
rc = seccomp_export_bpf(ctx, fd);
|
|
85
|
+
if (rc < 0) {
|
|
86
|
+
fprintf(stderr, "Error: Failed to export seccomp filter: %s\n", strerror(-rc));
|
|
87
|
+
close(fd);
|
|
88
|
+
seccomp_release(ctx);
|
|
89
|
+
return 1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* Clean up */
|
|
93
|
+
close(fd);
|
|
94
|
+
seccomp_release(ctx);
|
|
95
|
+
|
|
96
|
+
return 0;
|
|
97
|
+
}
|