A Deny-by-Default Manifest for AI-Generated Services on a Free Server MonkeyCode, as part of its product outreach, has published a deny-by-default manifest and a static analysis preflight script to help developers secure AI-generated services deployed on free servers. The approach treats a free server as a real security boundary by requiring a capability contract before deployment, with checks for banned imports and file access outside declared paths. The manifest includes explicit listen ports, filesystem read/write paths, empty outbound network hosts, and environment variable denials. Why this is worth reading: a free model can hand you a working service in one prompt, and a free server can publish it before you have read the control flow. The cheap path tends to skip the permissions conversation. This article gives you a deny-by-default manifest and a bubblewrap preflight so you can treat a free server as a real boundary without buying extra infrastructure. If you are using MonkeyCode's free model access and free server option, the convenience is real, not an excuse to skip host hygiene. Disclosure: This article was prepared as part of MonkeyCode's product outreach. I am not going to assume model names, quotas, or how long the free server stays alive; the manifest below works whether your process is a shared worker or an isolated container. You ask a free model for a small service and it returns code that looks finished. You deploy it to the free server because the cost of trying is nearly zero, and you skip the review that a paid environment would force you to schedule. A free tier lowers the cost of exploration, but it also lowers the cost of not declaring what the service may touch. A log write to /tmp becomes a write to shared disk, an outbound call to an analytics endpoint creates a dependency you did not choose, and a stray open can read a config file that the service never needed. The fix is to write a capability contract before you deploy, then make the preflight fail on any undeclared capability. You can ask the model to suggest a manifest, but you should be the one to commit it. A server contract is a review artifact, not a generation artifact. Here is the smallest version that is still useful: { "service": "weather-echo", "entrypoint": "python app.py", "listen": {"ports": 8080 , "bind": "127.0.0.1"}, "filesystem": { "read": "data/config.json" , "write": "data/cache/" }, "network": { "outbound hosts": }, "env": { "read": "PORT" , "deny": "DATABASE URL", "SECRET KEY", "AWS " }, "resources": { "max cpu seconds": 10, "max memory mb": 128 } } You keep listen explicit because a free server often provides a port through an environment variable and nothing else. You keep filesystem explicit because a shared free process can still write to the working directory. You keep network.outbound hosts empty by default because a simple service should not start with full egress. The resources keys are aspirational on some free tiers, but they still record the ceiling you intended to enforce. Static analysis is not a security boundary, but it catches the obvious undeclared imports and literal file paths before you spend time on a runtime sandbox. The following checker reads server-contract.json , parses the target Python file, and fails on banned modules or open calls outside the allowed paths. python /usr/bin/env python3 import ast import json import os import sys contract = json.load open 'server-contract.json' read paths = {os.path.abspath p for p in contract 'filesystem' 'read' } write paths = {os.path.abspath p.rstrip '/' for p in contract 'filesystem' 'write' } banned modules = {'subprocess', 'socket', 'requests', 'urllib.request'} def check file path : tree = ast.parse open path, encoding='utf-8' .read , filename=path for node in ast.walk tree : if isinstance node, ast.Import : for alias in node.names: assert alias.name.split '.' 0 not in banned modules, f'banned import {alias.name} in {path}' if isinstance node, ast.ImportFrom : assert node.module.split '.' 0 not in banned modules, f'banned import from {node.module} in {path}' if isinstance node, ast.Call and getattr node.func, 'id', None == 'open': if node.args and isinstance node.args 0 , ast.Constant : target = os.path.abspath node.args 0 .value mode = node.args 1 .value if len node.args 1 and isinstance node.args 1 , ast.Constant else 'r' allowed = write paths if any m in mode for m in 'w', 'a', 'x', '+' else read paths | write paths assert target in allowed or any target.startswith p + os.sep for p in allowed , f'open outside manifest: {target} in {path}' if name == ' main ': for path in sys.argv 1: : check file path print 'static contract check passed' You run it with python check contract.py app.py . The script does not understand dynamic paths or indirect imports, so a clean result means only that there is less obvious surface to review. It is a first filter, not a finding of safety. You can use bubblewrap on Linux to create a small sandbox with a read-only application directory and a single writable data directory. The command below drops user, PID, IPC, and UTS namespaces while sharing the network with the host, so you can still smoke-test the local port. bash /usr/bin/env bash set -euo pipefail python check contract.py app.py mkdir -p data bwrap --ro-bind /usr /usr --ro-bind /lib /lib --ro-bind /lib64 /lib64 --ro-bind "$ pwd " /app --bind "$ pwd /data" /app/data --dev /dev --proc /proc --chdir /app --unshare-user --unshare-pid --unshare-ipc --unshare-uts --die-with-parent python app.py & pid=$ trap 'kill "$pid" 2 /dev/null || true' EXIT sleep 1 curl -sSf http://127.0.0.1:8080/health echo 'preflight passed' You may need to adjust the /usr , /lib , and /lib64 bind mounts for your distro or base image. The point of the command is not to make every service portable; the point is to make the intended writable surface explicit and to stop the service from carrying more privileges than the manifest declares. You should verify the gate by adding a known violation before you trust it. Change one line in app.py so it writes to /tmp/canary , then run python check contract.py app.py and watch it fail. Then try running a network attempt inside a network namespace you did not share: python bwrap --unshare-net python -c "import socket; socket.create connection 'example.com', 80 , timeout=2 " If the command fails to connect, the network isolation is doing its job. If it succeeds, your wrapper is not applying the flag you expected and the preflight is not a real gate. A passing test that you have never forced to fail is just a ritual. You should not read this as a replacement for platform-level enforcement. Static analysis misses dynamic file paths and imports; bubblewrap does not enforce an outbound-host allowlist when you share the host network; and a free server platform may run your process with different user, network, or filesystem policies than your laptop. The manifest is a statement of intent that you still need to enforce on the platform or in a real container with a network policy. It also does not prove the generated code is correct or safe; it only catches capability drift you already decided to reject. You should skip this approach if the service touches customer data, regulated data, multi-tenant workloads, or anything with an availability obligation. In those cases you need a maintained container or cluster with network policies, not a free server and a local sandbox. You should also skip it if the service legitimately needs wide outbound access; a deny-by-default network section will fight you on every upstream change and may push you to weaken the manifest instead of tighten the design. When you next stand up a service generated by a free model on a free server, write the manifest first. If MonkeyCode's free server option is the destination, keep that manifest in your repository, not in the platform defaults. The gate should fail before your public endpoint does.