Audit findings: BUG-R2-S2-A6-H2 + BUG-R2-S2-A6-H3 | CWE-400 / CWE-401 | CVSS 7.7 / 6.3 | PoC: reproduced, EXP confirmed
Summary
SecureCodeExecutor._run_in_container (secure_code_executor.py:279-291) configures mem_limit/cpu_quota/network_mode but leaves three containment gaps:
- No
log_config — the daemon's default json-file driver is unbounded (no max-size/max-file; repo ships no daemon.json). Sandbox stdout is written by dockerd to /var/lib/docker/containers/<id>/<id>-json.log on the daemon host, outside every container resource limit. POC-measured: a gate-compliant while True: print('A' * 10000) wrote 2.30 GB in one 10 s window (~230 MB/s) while container memory stayed at ~15.7 MB. EXP-measured full cascade: one request hit ENOSPC on a modeled host disk, dockerd container-start failed, stats engine down for all tenants, co-hosted services failing until manual docker rm.
remove=False with zero removal sites — repo-wide grep finds no .remove()/.prune()/docker rm anywhere. Every execution (benign or malicious) leaks one stopped container plus its full log file, indefinitely.
- No
pids_limit — process count is the one kernel resource left unbounded. Spawn primitives that pass all gates (see companion executor-gate-bypass issue): import posix + chr-built shell fork bomb, or multiprocessing.Pool(99999) — every fork allocates a host PID up to kernel.pid_max; host-wide fork-failure DoS during each 10 s window, sustained at ~5-9 windows/min within the per-key rate limit.
Envelope: live where the API shares a filesystem with the Docker daemon (documented bare-metal mode); shipped compose/k8s fail closed; socket-compose mode still leaks containers.
Suggested fix
containers.run(
...,
log_config=LogConfig(type=LogConfig.types.JSON,
config={"max-size": "10m", "max-file": "1"}),
pids_limit=128,
)
# and in finally:
container.remove(force=True)
(Result read-back uses the mounted result.json, never container logs, so removal after wait()/kill() is safe.) Defense in depth: daemon-wide json-file rotation.
Related: #322 (sandbox hardening — commented with these findings).
Source: OpenVuln external audit of QWED-AI/qwed-verification (snapshot v7.0.0, re-verified against current main v7.1.0). All code anchors below were spot-checked against current main before filing.
Audit findings:
BUG-R2-S2-A6-H2+BUG-R2-S2-A6-H3| CWE-400 / CWE-401 | CVSS 7.7 / 6.3 | PoC: reproduced, EXP confirmedSummary
SecureCodeExecutor._run_in_container(secure_code_executor.py:279-291) configuresmem_limit/cpu_quota/network_modebut leaves three containment gaps:log_config— the daemon's default json-file driver is unbounded (no max-size/max-file; repo ships no daemon.json). Sandbox stdout is written by dockerd to/var/lib/docker/containers/<id>/<id>-json.logon the daemon host, outside every container resource limit. POC-measured: a gate-compliantwhile True: print('A' * 10000)wrote 2.30 GB in one 10 s window (~230 MB/s) while container memory stayed at ~15.7 MB. EXP-measured full cascade: one request hit ENOSPC on a modeled host disk, dockerd container-start failed, stats engine down for all tenants, co-hosted services failing until manualdocker rm.remove=Falsewith zero removal sites — repo-wide grep finds no.remove()/.prune()/docker rmanywhere. Every execution (benign or malicious) leaks one stopped container plus its full log file, indefinitely.pids_limit— process count is the one kernel resource left unbounded. Spawn primitives that pass all gates (see companion executor-gate-bypass issue):import posix+ chr-built shell fork bomb, ormultiprocessing.Pool(99999)— every fork allocates a host PID up tokernel.pid_max; host-wide fork-failure DoS during each 10 s window, sustained at ~5-9 windows/min within the per-key rate limit.Envelope: live where the API shares a filesystem with the Docker daemon (documented bare-metal mode); shipped compose/k8s fail closed; socket-compose mode still leaks containers.
Suggested fix
(Result read-back uses the mounted
result.json, never container logs, so removal afterwait()/kill()is safe.) Defense in depth: daemon-wide json-file rotation.Related: #322 (sandbox hardening — commented with these findings).
Source: OpenVuln external audit of QWED-AI/qwed-verification (snapshot v7.0.0, re-verified against current
mainv7.1.0). All code anchors below were spot-checked against current main before filing.