An API to execute code snippets in multiple languages and return the output and execution metrics
See the codeThe general idea of this project is to provide a service similar to the CodeExecutionAPI by The Alcoding Club but to manually implement the containerization using cgroups, namespaces, chroot and a bunch of other unix/linux utility tools. This will help accomplish faster execution times and cut down on sandboxing overhead
To use this API, there aren't really any requirements, you just need to be able to send HTTP requests To Host this API, you need to have Linux or WSL (if you're on windows) or MacOS, because this project makes heavy use of unix-specific tools.
Using this API is designed to be as simple as possible, at it's core, it's just an HTTP request that you send to /v2/execute, or /execute
The following are the routes that this API makes available, click one to see it's documentation
This route is a drop in replacement for CodeExecutionAPI, if you send any request to the API defined in that repository, it's actually going to be handled by this codebase (because it does the same exact thing but faster)
This route takes 4 fields:
| Parameter | What It Does | Default & Limits | How To Use |
|---|---|---|---|
| language | Specifies which programming language to execute your code in. The API needs to know which compiler/interpreter to use. | Required (no default) Supported values: • python - Python 3.x• cpp - C++17 (G++)• c - C11 (GCC)• java - Java (OpenJDK) | Pass as a string. Must exactly match one of the supported values (all lowercase). Example: "language": "python" |
| code | The actual source code you want to run. This is what gets executed in the isolated environment. | Required (no default) No explicit size limit | Pass as a single string. Use \n for line breaks. Escape any quotes inside your code.Single line: "code": "print('Hello')"Multi-line: "code": "def hello():\n print('world')\nhello()" |
| timeout | Maximum execution time. If your code runs longer than this, it gets killed immediately to prevent infinite loops or runaway processes. | Default: 5 secondsMax: 60 seconds | Pass as an integer (seconds). Your code will be terminated the moment it exceeds this limit. On timeout: Returns "Execution Timed Out" error with no output.Example: "timeout": 10 (runs for max 10 seconds) |
| max_memory | Maximum RAM your code can use. If your code allocates more memory than this, it gets killed to prevent memory exhaustion. | Default: 32768 KB (32 MB)Max: 131072 KB (128 MB) | Pass as an integer (KB). Memory is monitored in real-time during execution. On limit exceeded: Returns "Memory limit exceeded" error.Example: "max_memory": 65536 (allows up to 64 MB) |
| inputs | Provides STDIN data for programs that read user input. Each array element becomes one line of input, delivered in order as your code calls input(), scanf(), etc. | Default: [] (no input)No explicit size limit | Pass as an array of strings. Each string is one line of input. Elements are consumed sequentially. Single input: "inputs": ["bob"]Multiple inputs: "inputs": ["bob", "alice", "25"]Use this if your code reads from STDIN |
Note: the above mentioned default and max values can be modified by editing the environment variables mentioned at the bottom of this README
{
"language": "python", // this is the language your code is going to be executed in
"code": "print('Hello World')" // a string containing the code itself, with lines separated by \n
}
curl --location 'https://codeapi.anga.codes/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "print('\''Hello World'\'')"
}'
{
"output": "Hello World\n", // Output of the code
"error": "", // If any error occurs during execution
"memory_used": "13808 KB", // RAM used (in KB)
"cpu_time": "9.166097ms" // as in 9.16 milliseconds
}
{
"language": "python",
"code": "import time\nprint('Hello World')\ntime.sleep(5)",
"timeout": 2 // in seconds (defaults to 5, max 60)
}
curl --location 'https://codeapi.anga.codes/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "import time\nprint('\''Hello World'\'')\ntime.sleep(5)",
"timeout": 2
}'
{
"output": "", // No output is returned on timeout
"error": "Execution Timed Out", // Error message in case of timeout
"memory_used": "15856 KB", // RAM used (in KB)
"cpu_time": "2.00014463s" // Time before code was terminated
}
{
"language": "python",
"code": "import random;[random.random() for x in range(10**7)]",
"max_memory": 300000 // in KB (defaults to 32768, max 131072)
}
curl --location 'https://codeapi.anga.codes/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "import random;[random.random() for x in range(10**7)]",
"max_memory": 300000
}'
{
"output": "",
"error": "Memory limit exceeded", // code is terminated the moment it takes more memory than allocated
"memory_used": "136636 KB",
"cpu_time": "115.779962ms"
}
{
"language": "python",
"code": "a = input()\nprint(f'first value entered is {a}.')\nb=input()\nprint(f'second value entered is {b}.')",
"inputs": [
"bob",
"alice"
]
}
curl --location 'https://codeapi.anga.codes/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "a = input()\nprint(f'\''first value entered is {a}.'\'')\nb=input()\nprint(f'\''second value entered is {b}.'\'')",
"inputs": [
"bob",
"alice"
]
}'
{
"output": "first value entered is bob.\nsecond value entered is alice.\n",
"error": "",
"memory_used": "24504 KB",
"cpu_time": "13.625964ms"
}
Note: the route /execute also calls /v2/execute under the hood, its just that the formatting for the input and output are slightly more easy to read and understand.
This route takes 4 fields:
| Parameter | Description | Default | Maximum |
|---|---|---|---|
| language | The programming language of the code snippet to be executed. | Required (no default) | N/A |
| code | The actual source code to be executed. Use \n to represent line breaks within the string. The code runs in an isolated environment. | Required (no default) | No explicit limit |
| timeout | Maximum execution time in nanoseconds. If the code runs longer than this, it will be forcefully terminated. | 5,000,000,000 ns(5 seconds) | 60,000,000,000 ns(60 seconds) |
| max_memory | Maximum memory allocation in KB (kilobytes). If the code exceeds this limit, it will be terminated immediately. | 32,768 KB(32 MB) | 131,072 KB(128 MB) |
| inputs | A single string containing all STDIN data. If your code reads input (e.g., input() in Python, scanf() in C, Scanner in Java), provide the input here. For multiple lines, separate them with \n. | Empty string (no input) | No explicit limit |
Note: the above mentioned default and max values can be modified by editing the environment variables mentioned at the bottom of this README
{
"language": "python",
"code": "print('Hello World')"
}
curl --location 'https://codeapi.anga.codes/v2/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "print('\''Hello World'\'')"
}'
{
"output": "Hello World\n", // output from STDOUT
"error": "", // output from STDERR
"cpu_time": 10283909, // run time in nanoseconds (10ms or 0.01 seconds)
"memory_used": 25116 // RAM used (in KB)
}
{
"language": "python",
"code": "import time\nprint('Hello World')\ntime.sleep(5)",
"timeout": 2000000000 // in nanoseconds (defaults to 5000000000, max 60000000000)
}
curl --location 'https://codeapi.anga.codes/v2/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "import time\nprint('\''Hello World'\'')\ntime.sleep(5)",
"timeout": 2000000000
}'
{
"output": "", // No output is returned on timeout
"error": "Execution Timed Out", // Error message in case of timeout
"cpu_time": 2000003280, // Time (in nanoseconds) before code was terminated
"memory_used": 15856, // RAM used (in KB)
}
{
"language": "python",
"code": "import random;[random.random() for x in range(10**7)]",
"max_memory": 300000 // in KB (defaults to 32768, max 131072)
}
curl --location 'https://codeapi.anga.codes/v2/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "import random;[random.random() for x in range(10**7)]",
"max_memory": 300000
}'
{
"output": "",
"error": "Memory limit exceeded", // code is terminated the moment it takes more memory than allocated
"cpu_time": 116936122,
"memory_used": 136628
}
{
"language": "python",
"code": "a = input()\nprint(f'first value entered is {a}.')\nb=input()\nprint(f'second value entered is {b}.')",
"inputs": "bob\nalice"
}
curl --location 'https://codeapi.anga.codes/v2/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "a = input()\nprint(f'\''first value entered is {a}.'\'')\nb=input()\nprint(f'\''second value entered is {b}.'\'')",
"inputs": "bob\nalice"
}'
{
"output": "first value entered is bob.\nsecond value entered is alice.\n",
"error": "",
"cpu_time": 9058716,
"memory_used": 25136
}
This route returns the current server configuration, including memory limits and timeout settings. This is a debug route and must be enabled via the ENABLE_DEBUG environment variable.
GET /debug/config
curl --location 'https://codeapi.anga.codes/debug/config'
{
"limits": {
"max_timeout": 60000000000,
"max_memory_limit": 131072,
"default_timeout": 5000000000,
"default_memory_limit": 32768
},
"globals": {
"ram_limit": 1048576,
"enable_debug_routes": false
}
}
I'm making this as part of a bigger project to host my own coding contests on a platform a little better than HackerRank. The Alcoding Club's API is fine but I need one that's more efficient and has less overhead than firejail.
MAX_TIMEOUT: This is the maximum timeout that a request can set, if an incoming request has a higher timeout than the value you set here, then it will ignore the request's set timeout only be executed for MAX_TIMEOUT time.
1m30s, 4h15s, 5s60s60sMAX_MEMORY_LIMIT: Maximum RAM allocation that a request can be set to, if an incoming request tries to set to a higher memory limit, it will be ignored and reset to this value
131072 which is 128 MB or 131072 KB131072DEFAULT_TIMEOUT: If an incoming request does not have a timeout parameter (i.e, request does not specify a time limit) then the sandbox will set the time limit to this value
MAX_TIMEOUT5s5sDEFAULT_MEMORY_LIMIT: If an incoming request does not have a max_memory parameter (i.e, request does not specify a memory limit) then the sandbox will set the maximum memory limit to this value
MAX_MEMORY_LIMIT32 MB32 MBGLOBAL_RAM_LIMIT: The total amount of RAM that is available globally to the server, cumulatively, the API will not allocate more RAM than what you define here, for example, if RAM limit if 1GB, and there are already 10 sandboxes that have reserved 100MB (either by default or by user-specification in the max_memory parameter) and an 11th process tries to reserve even more RAM, the server will NOT allocate that RAM
MAX_MEMORY_LIMIT1048576 or 1 GB1 GBENABLE_DEBUG: if true, the server will expose debug routes (like /check-ram) for monitoring and debugging purposes
true or falsefalsetrueGIN_MODE: whether to run the gin-gonic server in release mode or debug mode. For this API there won't be much of a performance difference regardless of which one you pick, and it is recommended that you read the docs for gin-gonic for more information
release or debugdebugreleasePORT: Which network port to run the server on
0 and 6553580808080Note: if you are self-hosting this api, remember to run it with superuser permissions, or a user which has permissions to alter controlgroups and namespaces, normally you can achieve this just by using "sudo" before running the code
This security verification suite is intended only for those users who want to self-host this API, the tests detailed below are for verifying if the sandboxing implemented by the codebase for running arbitrary user code is compatible with the host where the tests are running, run these commands on your host to verify that it's suitable for the kind of sandboxing I've implemented here. If one or more of these tests is failing then its probably a good idea to self-host this api inside of another more hardened container/VM. The host running the publically deployed version of this API is completely compatible with the sandboxing used in this codebase and is safe to use, but your host might not be.
Run these safe checks on the host:
uname -a
test "$(uname -s)" = Linux
test -r /proc/self/status
test -e /sys/fs/cgroup/cgroup.controllers
test -e /proc/self/ns/user
test -e /proc/self/ns/pid
command -v gcc
command -v go
command -v python3
The integration suite also requires a writable cgroup v2 hierarchy, working user namespaces, and permission to create the required namespaces. Java tests additionally require java and javac. Check active mandatory access-control policy with the host's normal tools, for example command -v getenforce && getenforce for SELinux or command -v aa-status && sudo aa-status for AppArmor. A policy mismatch is an investigation item, not a reason to disable isolation.
From the repository root, run:
sudo -E go test ./...
sudo -E go test -race ./executor
bash .github/scripts/check_regressions.sh
git diff --check
Run the repeated hostile boundary probe with:
sudo -E go test -count=3 -run '^TestSecurityBoundaryNamespacesAndInheritedResources$' ./...
sudo -E go test -count=3 -run '^TestSandboxHardeningC$/^hostile boundary attack chain cannot cross sandbox$' ./...
sudo is required because the test harness intentionally exercises privileged Linux isolation and cgroup operations. Never ignore a failed command, add || true, or treat a skipped privileged test as success.
Use a disposable directory, never a real secret:
sentinel_dir=$(mktemp -d)
printf '%s\n' 'operator-sentinel-must-not-change' > "$sentinel_dir/sentinel"
sha256sum "$sentinel_dir/sentinel"
sudo -E go test -run '^TestSecurityBoundaryNamespacesAndInheritedResources$' ./...
sha256sum "$sentinel_dir/sentinel"
rm -rf "$sentinel_dir"
The adversarial workload attempts filesystem, descriptor, procfs, sysfs, IPC, UTS, socket, and temporary-path access. The host sentinel must still exist with the same checksum. Delete the disposable sentinel manually after verification.
Review the test output and host state after the suite. Confirm that host files are unreadable and unchanged, host processes cannot be enumerated or signalled, devices and mounts cannot be manipulated, /sys cannot be written, Unix sockets are not reachable, host environment secrets and file descriptors are absent, the configured network policy holds, sandbox descendants disappear after termination, and sandbox temporary resources do not remain on the host.
For cross-sandbox verification, run the repeated boundary probe while another terminal runs sudo -E go test -count=10 -run '^TestSecurityBoundaryNamespacesAndInheritedResources$' ./.... Neither run may report inherited descriptors, host process access, IPC visibility, host socket access, or host sentinel changes.
Missing cgroup v2 means resource enforcement cannot be established. Missing user namespaces or insufficient privileges means namespace isolation cannot be established. Missing compiler/runtime dependencies mean the relevant workload coverage did not execute. Unexpected mounts, devices, security-module state, namespace creation errors, or seccomp failures indicate a host or implementation mismatch. Do not disable the corresponding security mechanism as a workaround; investigate or move the service to a dedicated hardened Linux VM.
Generic GitHub-hosted runners cannot prove every kernel, LSM, device, mount-topology, cloud-metadata, or privileged-host-socket property. Those checks require a dedicated hardened VM with pinned kernel configuration and explicit network/device policy. See SECURITY_TEST_MATRIX.md for the boundary-by-boundary status and assumptions.
An API to execute code snippets in multiple languages and return the output and execution metrics
See the codeThe general idea of this project is to provide a service similar to the CodeExecutionAPI by The Alcoding Club but to manually implement the containerization using cgroups, namespaces, chroot and a bunch of other unix/linux utility tools. This will help accomplish faster execution times and cut down on sandboxing overhead
To use this API, there aren't really any requirements, you just need to be able to send HTTP requests To Host this API, you need to have Linux or WSL (if you're on windows) or MacOS, because this project makes heavy use of unix-specific tools.
Using this API is designed to be as simple as possible, at it's core, it's just an HTTP request that you send to /v2/execute, or /execute
The following are the routes that this API makes available, click one to see it's documentation
This route is a drop in replacement for CodeExecutionAPI, if you send any request to the API defined in that repository, it's actually going to be handled by this codebase (because it does the same exact thing but faster)
This route takes 4 fields:
| Parameter | What It Does | Default & Limits | How To Use |
|---|---|---|---|
| language | Specifies which programming language to execute your code in. The API needs to know which compiler/interpreter to use. | Required (no default) Supported values: • python - Python 3.x• cpp - C++17 (G++)• c - C11 (GCC)• java - Java (OpenJDK) | Pass as a string. Must exactly match one of the supported values (all lowercase). Example: "language": "python" |
| code | The actual source code you want to run. This is what gets executed in the isolated environment. | Required (no default) No explicit size limit | Pass as a single string. Use \n for line breaks. Escape any quotes inside your code.Single line: "code": "print('Hello')"Multi-line: "code": "def hello():\n print('world')\nhello()" |
| timeout | Maximum execution time. If your code runs longer than this, it gets killed immediately to prevent infinite loops or runaway processes. | Default: 5 secondsMax: 60 seconds | Pass as an integer (seconds). Your code will be terminated the moment it exceeds this limit. On timeout: Returns "Execution Timed Out" error with no output.Example: "timeout": 10 (runs for max 10 seconds) |
| max_memory | Maximum RAM your code can use. If your code allocates more memory than this, it gets killed to prevent memory exhaustion. | Default: 32768 KB (32 MB)Max: 131072 KB (128 MB) | Pass as an integer (KB). Memory is monitored in real-time during execution. On limit exceeded: Returns "Memory limit exceeded" error.Example: "max_memory": 65536 (allows up to 64 MB) |
| inputs | Provides STDIN data for programs that read user input. Each array element becomes one line of input, delivered in order as your code calls input(), scanf(), etc. | Default: [] (no input)No explicit size limit | Pass as an array of strings. Each string is one line of input. Elements are consumed sequentially. Single input: "inputs": ["bob"]Multiple inputs: "inputs": ["bob", "alice", "25"]Use this if your code reads from STDIN |
Note: the above mentioned default and max values can be modified by editing the environment variables mentioned at the bottom of this README
{
"language": "python", // this is the language your code is going to be executed in
"code": "print('Hello World')" // a string containing the code itself, with lines separated by \n
}
curl --location 'https://codeapi.anga.codes/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "print('\''Hello World'\'')"
}'
{
"output": "Hello World\n", // Output of the code
"error": "", // If any error occurs during execution
"memory_used": "13808 KB", // RAM used (in KB)
"cpu_time": "9.166097ms" // as in 9.16 milliseconds
}
{
"language": "python",
"code": "import time\nprint('Hello World')\ntime.sleep(5)",
"timeout": 2 // in seconds (defaults to 5, max 60)
}
curl --location 'https://codeapi.anga.codes/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "import time\nprint('\''Hello World'\'')\ntime.sleep(5)",
"timeout": 2
}'
{
"output": "", // No output is returned on timeout
"error": "Execution Timed Out", // Error message in case of timeout
"memory_used": "15856 KB", // RAM used (in KB)
"cpu_time": "2.00014463s" // Time before code was terminated
}
{
"language": "python",
"code": "import random;[random.random() for x in range(10**7)]",
"max_memory": 300000 // in KB (defaults to 32768, max 131072)
}
curl --location 'https://codeapi.anga.codes/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "import random;[random.random() for x in range(10**7)]",
"max_memory": 300000
}'
{
"output": "",
"error": "Memory limit exceeded", // code is terminated the moment it takes more memory than allocated
"memory_used": "136636 KB",
"cpu_time": "115.779962ms"
}
{
"language": "python",
"code": "a = input()\nprint(f'first value entered is {a}.')\nb=input()\nprint(f'second value entered is {b}.')",
"inputs": [
"bob",
"alice"
]
}
curl --location 'https://codeapi.anga.codes/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "a = input()\nprint(f'\''first value entered is {a}.'\'')\nb=input()\nprint(f'\''second value entered is {b}.'\'')",
"inputs": [
"bob",
"alice"
]
}'
{
"output": "first value entered is bob.\nsecond value entered is alice.\n",
"error": "",
"memory_used": "24504 KB",
"cpu_time": "13.625964ms"
}
Note: the route /execute also calls /v2/execute under the hood, its just that the formatting for the input and output are slightly more easy to read and understand.
This route takes 4 fields:
| Parameter | Description | Default | Maximum |
|---|---|---|---|
| language | The programming language of the code snippet to be executed. | Required (no default) | N/A |
| code | The actual source code to be executed. Use \n to represent line breaks within the string. The code runs in an isolated environment. | Required (no default) | No explicit limit |
| timeout | Maximum execution time in nanoseconds. If the code runs longer than this, it will be forcefully terminated. | 5,000,000,000 ns(5 seconds) | 60,000,000,000 ns(60 seconds) |
| max_memory | Maximum memory allocation in KB (kilobytes). If the code exceeds this limit, it will be terminated immediately. | 32,768 KB(32 MB) | 131,072 KB(128 MB) |
| inputs | A single string containing all STDIN data. If your code reads input (e.g., input() in Python, scanf() in C, Scanner in Java), provide the input here. For multiple lines, separate them with \n. | Empty string (no input) | No explicit limit |
Note: the above mentioned default and max values can be modified by editing the environment variables mentioned at the bottom of this README
{
"language": "python",
"code": "print('Hello World')"
}
curl --location 'https://codeapi.anga.codes/v2/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "print('\''Hello World'\'')"
}'
{
"output": "Hello World\n", // output from STDOUT
"error": "", // output from STDERR
"cpu_time": 10283909, // run time in nanoseconds (10ms or 0.01 seconds)
"memory_used": 25116 // RAM used (in KB)
}
{
"language": "python",
"code": "import time\nprint('Hello World')\ntime.sleep(5)",
"timeout": 2000000000 // in nanoseconds (defaults to 5000000000, max 60000000000)
}
curl --location 'https://codeapi.anga.codes/v2/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "import time\nprint('\''Hello World'\'')\ntime.sleep(5)",
"timeout": 2000000000
}'
{
"output": "", // No output is returned on timeout
"error": "Execution Timed Out", // Error message in case of timeout
"cpu_time": 2000003280, // Time (in nanoseconds) before code was terminated
"memory_used": 15856, // RAM used (in KB)
}
{
"language": "python",
"code": "import random;[random.random() for x in range(10**7)]",
"max_memory": 300000 // in KB (defaults to 32768, max 131072)
}
curl --location 'https://codeapi.anga.codes/v2/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "import random;[random.random() for x in range(10**7)]",
"max_memory": 300000
}'
{
"output": "",
"error": "Memory limit exceeded", // code is terminated the moment it takes more memory than allocated
"cpu_time": 116936122,
"memory_used": 136628
}
{
"language": "python",
"code": "a = input()\nprint(f'first value entered is {a}.')\nb=input()\nprint(f'second value entered is {b}.')",
"inputs": "bob\nalice"
}
curl --location 'https://codeapi.anga.codes/v2/execute' \
--header 'Content-Type: application/json' \
--data '{
"language": "python",
"code": "a = input()\nprint(f'\''first value entered is {a}.'\'')\nb=input()\nprint(f'\''second value entered is {b}.'\'')",
"inputs": "bob\nalice"
}'
{
"output": "first value entered is bob.\nsecond value entered is alice.\n",
"error": "",
"cpu_time": 9058716,
"memory_used": 25136
}
This route returns the current server configuration, including memory limits and timeout settings. This is a debug route and must be enabled via the ENABLE_DEBUG environment variable.
GET /debug/config
curl --location 'https://codeapi.anga.codes/debug/config'
{
"limits": {
"max_timeout": 60000000000,
"max_memory_limit": 131072,
"default_timeout": 5000000000,
"default_memory_limit": 32768
},
"globals": {
"ram_limit": 1048576,
"enable_debug_routes": false
}
}
I'm making this as part of a bigger project to host my own coding contests on a platform a little better than HackerRank. The Alcoding Club's API is fine but I need one that's more efficient and has less overhead than firejail.
MAX_TIMEOUT: This is the maximum timeout that a request can set, if an incoming request has a higher timeout than the value you set here, then it will ignore the request's set timeout only be executed for MAX_TIMEOUT time.
1m30s, 4h15s, 5s60s60sMAX_MEMORY_LIMIT: Maximum RAM allocation that a request can be set to, if an incoming request tries to set to a higher memory limit, it will be ignored and reset to this value
131072 which is 128 MB or 131072 KB131072DEFAULT_TIMEOUT: If an incoming request does not have a timeout parameter (i.e, request does not specify a time limit) then the sandbox will set the time limit to this value
MAX_TIMEOUT5s5sDEFAULT_MEMORY_LIMIT: If an incoming request does not have a max_memory parameter (i.e, request does not specify a memory limit) then the sandbox will set the maximum memory limit to this value
MAX_MEMORY_LIMIT32 MB32 MBGLOBAL_RAM_LIMIT: The total amount of RAM that is available globally to the server, cumulatively, the API will not allocate more RAM than what you define here, for example, if RAM limit if 1GB, and there are already 10 sandboxes that have reserved 100MB (either by default or by user-specification in the max_memory parameter) and an 11th process tries to reserve even more RAM, the server will NOT allocate that RAM
MAX_MEMORY_LIMIT1048576 or 1 GB1 GBENABLE_DEBUG: if true, the server will expose debug routes (like /check-ram) for monitoring and debugging purposes
true or falsefalsetrueGIN_MODE: whether to run the gin-gonic server in release mode or debug mode. For this API there won't be much of a performance difference regardless of which one you pick, and it is recommended that you read the docs for gin-gonic for more information
release or debugdebugreleasePORT: Which network port to run the server on
0 and 6553580808080Note: if you are self-hosting this api, remember to run it with superuser permissions, or a user which has permissions to alter controlgroups and namespaces, normally you can achieve this just by using "sudo" before running the code
This security verification suite is intended only for those users who want to self-host this API, the tests detailed below are for verifying if the sandboxing implemented by the codebase for running arbitrary user code is compatible with the host where the tests are running, run these commands on your host to verify that it's suitable for the kind of sandboxing I've implemented here. If one or more of these tests is failing then its probably a good idea to self-host this api inside of another more hardened container/VM. The host running the publically deployed version of this API is completely compatible with the sandboxing used in this codebase and is safe to use, but your host might not be.
Run these safe checks on the host:
uname -a
test "$(uname -s)" = Linux
test -r /proc/self/status
test -e /sys/fs/cgroup/cgroup.controllers
test -e /proc/self/ns/user
test -e /proc/self/ns/pid
command -v gcc
command -v go
command -v python3
The integration suite also requires a writable cgroup v2 hierarchy, working user namespaces, and permission to create the required namespaces. Java tests additionally require java and javac. Check active mandatory access-control policy with the host's normal tools, for example command -v getenforce && getenforce for SELinux or command -v aa-status && sudo aa-status for AppArmor. A policy mismatch is an investigation item, not a reason to disable isolation.
From the repository root, run:
sudo -E go test ./...
sudo -E go test -race ./executor
bash .github/scripts/check_regressions.sh
git diff --check
Run the repeated hostile boundary probe with:
sudo -E go test -count=3 -run '^TestSecurityBoundaryNamespacesAndInheritedResources$' ./...
sudo -E go test -count=3 -run '^TestSandboxHardeningC$/^hostile boundary attack chain cannot cross sandbox$' ./...
sudo is required because the test harness intentionally exercises privileged Linux isolation and cgroup operations. Never ignore a failed command, add || true, or treat a skipped privileged test as success.
Use a disposable directory, never a real secret:
sentinel_dir=$(mktemp -d)
printf '%s\n' 'operator-sentinel-must-not-change' > "$sentinel_dir/sentinel"
sha256sum "$sentinel_dir/sentinel"
sudo -E go test -run '^TestSecurityBoundaryNamespacesAndInheritedResources$' ./...
sha256sum "$sentinel_dir/sentinel"
rm -rf "$sentinel_dir"
The adversarial workload attempts filesystem, descriptor, procfs, sysfs, IPC, UTS, socket, and temporary-path access. The host sentinel must still exist with the same checksum. Delete the disposable sentinel manually after verification.
Review the test output and host state after the suite. Confirm that host files are unreadable and unchanged, host processes cannot be enumerated or signalled, devices and mounts cannot be manipulated, /sys cannot be written, Unix sockets are not reachable, host environment secrets and file descriptors are absent, the configured network policy holds, sandbox descendants disappear after termination, and sandbox temporary resources do not remain on the host.
For cross-sandbox verification, run the repeated boundary probe while another terminal runs sudo -E go test -count=10 -run '^TestSecurityBoundaryNamespacesAndInheritedResources$' ./.... Neither run may report inherited descriptors, host process access, IPC visibility, host socket access, or host sentinel changes.
Missing cgroup v2 means resource enforcement cannot be established. Missing user namespaces or insufficient privileges means namespace isolation cannot be established. Missing compiler/runtime dependencies mean the relevant workload coverage did not execute. Unexpected mounts, devices, security-module state, namespace creation errors, or seccomp failures indicate a host or implementation mismatch. Do not disable the corresponding security mechanism as a workaround; investigate or move the service to a dedicated hardened Linux VM.
Generic GitHub-hosted runners cannot prove every kernel, LSM, device, mount-topology, cloud-metadata, or privileged-host-socket property. Those checks require a dedicated hardened VM with pinned kernel configuration and explicit network/device policy. See SECURITY_TEST_MATRIX.md for the boundary-by-boundary status and assumptions.