Skip to content
This repository was archived by the owner on Mar 14, 2026. It is now read-only.

Commit bd4e967

Browse files
koki-developclaude
andcommitted
Add 12 new sandbox security exploit tests
Cover additional attack vectors: memory/CPU/inode exhaustion, stderr flood, symlink escape, privilege escalation, device access, rlimit override, signal resistance, read-only write, /proc info leak, and environment variable leakage. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 91a51e5 commit bd4e967

13 files changed

Lines changed: 314 additions & 0 deletions

AGENTS.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ codize run --json tests/network.py # Network access test
110110
codize run --json tests/runaway_output.py # Infinite output test
111111
codize run --json tests/file_persistance.py # File persistence test (run twice)
112112
codize run --json tests/mqueue_persistance.py # Mqueue persistence test (run twice)
113+
codize run --json tests/memory_exhaustion.py # Memory exhaustion test
114+
codize run --json tests/inode_exhaustion.py # Inode exhaustion test
115+
codize run --json tests/symlink_escape.py # Symlink escape test
116+
codize run --json tests/privilege_escalation.py # Privilege escalation test
117+
codize run --json tests/device_access.py # Device access test
118+
codize run --json tests/stderr_flood.py # Stderr flood test
119+
codize run --json tests/cpu_exhaustion.py # CPU exhaustion test
120+
codize run --json tests/env_leakage.py # Environment variable leakage test
121+
codize run --json tests/rlimit_override.py # Resource limit override test
122+
codize run --json tests/signal_resistance.py # Signal resistance test
123+
codize run --json tests/readonly_write.py # Read-only filesystem write test
124+
codize run --json tests/proc_info_leak.py # /proc information leakage test
113125
```
114126
115127
Package tests are automatically executed via GitHub Actions (`package-pr.yaml`).

tests/cpu_exhaustion.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""
2+
Description
3+
Pure CPU busy-loop with no I/O or sleep, designed to exhaust the
4+
CPU time limit enforced by the sandbox cgroup controller
5+
6+
The sandbox should terminate the process once the CPU time limit
7+
is exceeded, returning a timeout status
8+
9+
"""
10+
11+
x = 0
12+
while True:
13+
x = (x * 6364136223846793005 + 1442695040888963407) & 0xFFFFFFFFFFFFFFFF

tests/device_access.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Description
3+
Attempting to open raw hardware devices including disk, memory, and
4+
kernel message devices that are bind-mounted from the host
5+
6+
The sandbox should prevent access to hardware device files by running
7+
as an unprivileged user without the necessary capabilities to open
8+
raw devices
9+
10+
"""
11+
12+
import os
13+
14+
devices = [
15+
"/dev/sda",
16+
"/dev/mem",
17+
"/dev/kmsg",
18+
"/dev/port",
19+
]
20+
21+
for dev in devices:
22+
if not os.path.exists(dev):
23+
continue
24+
try:
25+
fd = os.open(dev, os.O_RDONLY)
26+
data = os.read(fd, 16)
27+
os.close(fd)
28+
print(f"{dev}: READ SUCCEEDED - {repr(data)} (CRITICAL)")
29+
except PermissionError:
30+
pass
31+
except OSError:
32+
pass

tests/env_leakage.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
Description
3+
Enumerating all environment variables visible inside the sandbox to
4+
check whether host environment variables are unintentionally leaked
5+
6+
The sandbox should only expose explicitly configured environment
7+
variables, with no host-origin secrets or credentials present
8+
9+
"""
10+
11+
import os
12+
13+
env = dict(os.environ)
14+
print(f"Total env vars: {len(env)}")
15+
for key in sorted(env.keys()):
16+
print(f"{key}={env[key]}")

tests/inode_exhaustion.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""
2+
Description
3+
Creating a large number of small files to exhaust filesystem inodes
4+
on the shared tmpfs, potentially denying service to other jobs
5+
6+
The sandbox should terminate the process via timeout or filesystem
7+
quota before inode exhaustion can affect the host system
8+
9+
"""
10+
11+
import os
12+
13+
i = 0
14+
while True:
15+
try:
16+
with open(f"/tmp/f{i}", "w") as f:
17+
f.write("x")
18+
i += 1
19+
except OSError:
20+
print(f"Stopped at {i} files")
21+
break

tests/memory_exhaustion.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""
2+
Description
3+
Unbounded memory allocation to exhaust available RAM and potentially
4+
trigger an OOM condition on the host system
5+
6+
The sandbox should terminate the process before host memory is exhausted,
7+
either via a memory cgroup limit or a wall-time/CPU-time timeout
8+
9+
"""
10+
11+
import sys
12+
13+
chunks = []
14+
while True:
15+
chunks.append(b'x' * (1024 * 1024)) # Allocate 1 MB at a time

tests/privilege_escalation.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""
2+
Description
3+
Attempting to escalate to root privileges using setuid, setgid,
4+
and seteuid system calls from within the sandbox
5+
6+
The sandbox should run as an unprivileged user with no capabilities,
7+
making all privilege escalation attempts fail with permission errors
8+
9+
"""
10+
11+
import os
12+
import ctypes
13+
14+
results = {}
15+
16+
try:
17+
os.setuid(0)
18+
results["setuid(0)"] = "SUCCEEDED (CRITICAL)"
19+
except PermissionError:
20+
results["setuid(0)"] = "blocked"
21+
22+
try:
23+
os.setgid(0)
24+
results["setgid(0)"] = "SUCCEEDED (CRITICAL)"
25+
except PermissionError:
26+
results["setgid(0)"] = "blocked"
27+
28+
try:
29+
libc = ctypes.CDLL("libc.so.6", use_errno=True)
30+
ret = libc.seteuid(0)
31+
if ret == 0:
32+
results["seteuid(0)"] = "SUCCEEDED (CRITICAL)"
33+
else:
34+
results["seteuid(0)"] = f"blocked (errno={ctypes.get_errno()})"
35+
except Exception as e:
36+
results["seteuid(0)"] = f"error: {e}"
37+
38+
results["uid"] = os.getuid()
39+
results["gid"] = os.getgid()
40+
41+
for key, val in results.items():
42+
print(f"{key}: {val}")

tests/proc_info_leak.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""
2+
Description
3+
Reading /proc entries to check if host process information or
4+
sensitive kernel data is exposed through the procfs interface
5+
6+
The sandbox should isolate /proc with hidepid=2 and PID namespace,
7+
preventing access to host process information
8+
9+
"""
10+
11+
import os
12+
13+
# Try to list processes visible in /proc
14+
pids = [d for d in os.listdir("/proc") if d.isdigit()]
15+
print(f"Visible PIDs: {pids}")
16+
17+
# Try to read PID 1's info (outside PID namespace, this would be host init)
18+
sensitive_paths = [
19+
"/proc/1/cmdline",
20+
"/proc/1/environ",
21+
"/proc/1/maps",
22+
]
23+
24+
for path in sensitive_paths:
25+
try:
26+
with open(path, "r") as f:
27+
content = f.read(100)
28+
print(f"{path}: {repr(content[:50])}")
29+
except (PermissionError, FileNotFoundError, ProcessLookupError):
30+
pass

tests/readonly_write.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
Description
3+
Attempting to write files to read-only bind-mounted directories
4+
including /usr, /bin, /lib, and /etc
5+
6+
The sandbox should enforce read-only mount restrictions, causing all
7+
write attempts to these paths to fail with filesystem or permission
8+
errors
9+
10+
"""
11+
12+
import os
13+
14+
readonly_paths = [
15+
"/usr/local/pwned",
16+
"/bin/pwned",
17+
"/lib/pwned",
18+
"/etc/pwned",
19+
]
20+
21+
for path in readonly_paths:
22+
parent = os.path.dirname(path)
23+
if not os.path.exists(parent):
24+
continue
25+
try:
26+
with open(path, "w") as f:
27+
f.write("pwned")
28+
print(f"{path}: WRITE SUCCEEDED (CRITICAL)")
29+
os.unlink(path)
30+
except (PermissionError, OSError):
31+
pass

tests/rlimit_override.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""
2+
Description
3+
Attempting to raise resource limits using Python's resource module to
4+
bypass the rlimits set by the sandbox, such as increasing the maximum
5+
process count or file size limit beyond the configured hard limits
6+
7+
The sandbox should prevent raising resource limits beyond the hard
8+
limits configured by isolate, as the process has no CAP_SYS_RESOURCE
9+
capability
10+
11+
"""
12+
13+
import resource
14+
15+
limits_to_try = [
16+
("RLIMIT_NPROC", resource.RLIMIT_NPROC),
17+
("RLIMIT_FSIZE", resource.RLIMIT_FSIZE),
18+
("RLIMIT_NOFILE", resource.RLIMIT_NOFILE),
19+
]
20+
21+
for name, res in limits_to_try:
22+
soft, hard = resource.getrlimit(res)
23+
print(f"{name}: soft={soft}, hard={hard}")
24+
try:
25+
resource.setrlimit(res, (hard + 1, hard + 1))
26+
new_soft, new_hard = resource.getrlimit(res)
27+
print(f" RAISED to soft={new_soft}, hard={new_hard} (CRITICAL)")
28+
except (ValueError, resource.error):
29+
pass

0 commit comments

Comments
 (0)