DEV Community

Dakota Huang
Dakota Huang

Posted on

A Default-Deny Shell Is Not a Default-Deny Network: Probe What a Free Model Server Can Reach

A default-deny shell policy is not a default-deny network. Before you let a model-generated process run on a free server, know what the host can actually reach.

The gap

Most free-server sandboxing advice covers commands, files, and credentials. A process can still:

  • call 169.254.169.254 for cloud metadata
  • resolve internal names through DNS
  • reach RFC1918 services on ports 22, 6379, or 5432
  • exfiltrate through plain DNS queries

If the model writes code, that code inherits the server's network path. Denying bash is not enough when a Python one-liner can open a socket.

Where the free endpoint fits

The workflow uses MonkeyCode's free model access to generate code and its free server option as a disposable execution host. The server is not proof of safety. It is a test surface: if the egress probe fails, the host is not ready for generated code.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The probe

This is a contract check, not a full scanner. It takes a deny list and an allow list, then reports whether each target is reachable. The script is meant to run inside the same server and user context that will execute model output.

import socket

TIMEOUT = 2.0

DENY = [
    ("169.254.169.254", 80, "cloud metadata"),
    ("metadata.google.internal", 80, "GCP metadata"),
    ("10.0.0.1", 22, "RFC1918 gateway"),
    ("192.168.0.1", 6379, "LAN redis"),
]

ALLOW = [
    ("example.com", 443, "public TLS"),
]


def probe(host, port):
    s = socket.socket()
    s.settimeout(TIMEOUT)
    try:
        s.connect((host, port))
        s.close()
        return True
    except OSError:
        s.close()
        return False


failures = 0

for host, port, label in DENY:
    reachable = probe(host, port)
    print(f"DENY  {label:22} {host}:{port} -> {'REACHABLE' if reachable else 'blocked or unresolved'}")
    if reachable:
        failures += 1

for host, port, label in ALLOW:
    reachable = probe(host, port)
    print(f"ALLOW {label:22} {host}:{port} -> {'OK' if reachable else 'UNREACHABLE'}")
    if not reachable:
        failures += 1

if failures:
    raise SystemExit(f"{failures} contract violation(s)")

print("contract passed")
Enter fullscreen mode Exit fullscreen mode

What the results mean

Check Expected Failure means
DENY 169.254.169.254:80 blocked or unresolved model code could read cloud metadata
DENY metadata.google.internal:80 blocked or unresolved DNS or metadata path is exposed
DENY 10.0.0.1:22 blocked internal gateway is reachable
DENY 192.168.0.1:6379 blocked LAN Redis is reachable
ALLOW example.com:443 OK required egress is missing

A blocked response is not a full firewall test. It only proves that one configured target did not accept a TCP connection during that run.

Why egress belongs before execution

Network calls are easy to miss because they do not require a shell. A generated file can run and dial out without any command allowlist being touched.

  • shell deny lists cover commands you can predict
  • sockets cover destinations you forgot
  • metadata endpoints are high value on shared or free compute
  • DNS can leak hostnames even when TCP is blocked

Put the probe in a pre-run hook or startup healthcheck. Only enable model execution when the probe exits 0.

Reproduce it

  1. Copy the script into the free server.
  2. Edit DENY and ALLOW to match the host's network contract.
  3. Run python3 egress_probe.py.
  4. Save the output with the model run.
  5. Treat any DENY reachable result as a failed gate.

Do not run this from a laptop and assume the server has the same result. The probe must execute in the same Linux user, container, and network namespace as the generated code.

Limitations

  • It is not a firewall audit. It only checks the configured targets.
  • DNS failure is treated as blocked for deny targets, which may hide a DNS-only exfiltration path. Add a separate DNS probe if DNS egress is required.
  • UDP is not tested. Add UDP checks for DNS over UDP, QUIC, or syslog if the model could send datagrams.
  • The timeout can miss slow-but-open services. Tune TIMEOUT to fit the environment.
  • Some allow targets may be blocked by an egress proxy. That is a correct failure if the proxy is required, but it is not the same as a broken network.
  • The script checks TCP connect only. It does not check HTTP response content or TLS certificate validity.

Who should not rely on this

  • Teams with a managed egress firewall and existing audit tooling.
  • Local development environments where allow targets differ by region or VPN.
  • Anyone who wants a guarantee. This is a tripwire, not a security proof.

The useful move is not to trust the sandbox label. Probe the actual network path before a model-generated process gets a socket.

Run the same check against any free host, including MonkeyCode's free server option, before you attach model output to the network.

Top comments (0)