Repository navigation
A security release, and the one that closes the hole the quickstart itself
published: docker compose up served an unauthenticated POST /execute on
every interface, plus PostgreSQL on 5432 with postgres/postgres. Anyone
who followed the README was running remote code execution open to their
network. Upgrade before anything else.
The minor bump is the max_timeout ceiling below, not the security fixes: a
deployment whose job_types declare a timeout above max_timeout is now
refused at startup instead of quietly exceeding its own limit.
Security
--hostcan no longer bypass the fail-closed bind guard. The config
validator refusedapi_auth_enabled: falsetogether with a non-loopback
server_host, buttako-vm server --host 0.0.0.0resolved the host after
validation and handed it straight to uvicorn unchecked. The shipped
docker/Dockerfile.serverCMDdoes exactly that, over a baked-in config
with authentication disabled, sodocker compose uppublished an
unauthenticatedPOST /executecode-execution endpoint on every interface.
The CLI now re-applies the config's own rule (ensure_bind_host_allowed,
one rule shared by the validator and the CLI) to the host it actually binds,
and exits with a message naming all three ways out.
TAKO_VM_ALLOW_UNAUTHENTICATED_NETWORK_ACCESSis a new environment override
for the existing escape hatch, needed because container images bake in their
config file.docker-compose.yamlno longer publishes PostgreSQL on the host. The
postgresservice mapped5432:5432withpostgres/postgres
credentials; the API reaches it by service name over the compose network, so
the mapping only exposed the database to anything that could route to the
host. Credentials are now interpolated fromTAKO_VM_POSTGRES_USER/
TAKO_VM_POSTGRES_PASSWORD/TAKO_VM_POSTGRES_DBwith a placeholder
default. The API's own port is now published on127.0.0.1:8000only.- Rate limiting now runs before the authentication rejection. Failed-auth
requests returned 401 before reaching the limiter, so API-key brute force was
unmetered and the DoS control was inert against unauthenticated callers.
Identity is still resolved first, so authenticated clients keep their
per-key buckets. - A non-ASCII API key header no longer returns HTTP 500.
hmac.compare_digestraisesTypeErroron non-ASCIIstroperands; that
reached the middleware's catch-all, which logged a full traceback at ERROR
and returned 500 — an unauthenticated log-flood amplifier. Keys are now
compared as UTF-8 bytes.
Changed
- BREAKING: a configured job type may no longer declare a
timeoutabove
max_timeout(#146).max_timeoutis documented as the maximum allowed
execution timeout, but it only bounded explicit per-request overrides: a
request could name a job type whose default exceeded it and the worker would
run the larger value. The ceiling is now enforced on the effective timeout
at three layers — config validation, the API boundary, and the worker — so a
deployment whosejob_typesdeclare a timeout abovemax_timeoutis refused
at startup instead of quietly exceeding its own limit. Raisemax_timeoutto
cover the largest job type you run. default_timeoutnow applies to requests that name no job type. Such
requests previously resolved the built-in default job type's hardcoded 30s and
ignoreddefault_timeoutentirely; they now use the configured value. Both
are 30 out of the box, so this changes nothing unless the deployment sets
default_timeout.- The
timeoutrequest field accepts values up to 86,400 seconds rather
than being capped at 300 by the request schema (#146, fixes #143). This is an
absolute schema ceiling only — the deployment'smax_timeout(default 300)
still applies and rejects anything above it with HTTP 422, so the accepted
range is unchanged unless an operator raisesmax_timeout.