How do you disable Python 3.14's remote-attach debugging for a hardened deployment?
answer
- Turn it off where the process runs
- Startup-time setting, not runtime
- Environment variable, command-line option, build flag
- Hyphens, not underscores, in the option
- Ask the process itself whether it is enabled
basics
~20 sSet PYTHON_DISABLE_REMOTE_DEBUG in the environment of the process being attached to, pass -X disable-remote-debug on its command line, or build the interpreter with the --without-remote-debug configure option. All three apply to the target, at its startup.
solid answer
~50 sPEP 768 ships three opt-outs, and every one of them is read by the **target** process, not by the tool doing the attaching. At startup a process honours `PYTHON_DISABLE_REMOTE_DEBUG` in its own environment, or `-X disable-remote-debug` on its own command line; a build made with the `--without-remote-debug` configure option has no support at all. A running process reports its state with `sys.is_remote_debug_enabled()`, and because the setting is read during interpreter initialisation, mutating `os.environ` afterwards changes nothing. Two traps are worth naming: setting the variable in the shell where you run the debugger accomplishes exactly nothing, and an unknown `-X` name is accepted silently, so writing the option with underscores instead of hyphens leaves the feature fully enabled. Treat the switch as defence in depth: the real gate is the operating-system permission required to write another process's memory.
code
console · 1 linePYTHON_DISABLE_REMOTE_DEBUG=1 python3 -c "import sys; print(sys.is_remote_debug_enabled())"go deeper
Know that Python 3.14's attach feature can be turned off, and that you turn it off on the process being attached to rather than on your own machine. The environment variable name is the piece worth remembering.
Be able to list the three opt-outs and say when each is read: an environment variable and a command-line option at interpreter startup, and a configure option at build time. Mention that the process can report its own state.
Show you verify rather than assume: assert the setting inside the process, because a misspelled interpreter option is accepted silently. Be able to say plainly that the operating-system permission is the real gate and the switch is defence in depth.
Own the decision once, per image, and make it uniform. The failure worth preventing is a fleet where attachability varies by manifest, so pick build-time removal or gated availability, and make the state auditable rather than folklore.
### Three switches, one owner PEP 768 gave deployments a way to say no. The three opt-outs differ in scope and in when they take effect, but they share one property that is the source of most confusion in practice: **they are all properties of the process being attached to.** 1. **`PYTHON_DISABLE_REMOTE_DEBUG`** — an environment variable, read when the interpreter initialises. Set it in the container spec, the service unit, or whatever launches the process. Per-process, no rebuild, survives nothing but a restart of that process. 2. **`-X disable-remote-debug`** — the same thing on the command line, for a single run. Useful in a wrapper script or when the launcher owns the argv but not the environment. 3. **`--without-remote-debug`** — a build-time configure option. The support is not compiled in, so no environment or command line can turn it back on. This is the setting for an organisation that wants 'this interpreter cannot be attached to' as a property of the image itself, verifiable once at build time rather than on every launch. ### Verifying, not assuming A process reports its own state through `sys.is_remote_debug_enabled()`, which returns `False` when any of the three has taken effect. This matters more than it looks, because the failure mode of the command-line switch is silent: CPython accepts unknown `-X` names without complaint, so a run started with the option name spelled with underscores instead of hyphens starts happily with remote debugging still on. Nothing warns you. If the setting is load-bearing for you, assert it inside the process rather than trusting the launch configuration, and check it in whatever health or diagnostics surface you already expose. The environment variable has a matching trap of its own: it is read at interpreter startup, so assigning to `os.environ` later has no effect on the running process, and setting it in the operator's own shell affects only interpreters that shell subsequently starts. If you set it where you run the debugging tool and then find you can still attach, the setting simply never reached the process you attached to. Note also that disabling the feature does not remove `sys.remote_exec` from the `sys` module; the attribute is still there. What changes is the target's willingness to act on a request, so introspecting for the attribute is not a valid check. ### What the switch is actually for It is worth being honest about the threat model, because candidates often oversell this. Attaching requires the ability to write another process's address space: on Linux, the same user plus the platform's tracing policy; on macOS, root or the task-port entitlement, which is why an ordinary shell cannot even attach to its own child. Anyone holding that capability can already read your process's memory, patch its code, and extract its secrets by other means. Turning off remote debugging does not take that away. What it does give you is a narrower, auditable statement: this interpreter offers no supported, low-friction, in-process code-injection channel. That is worth having in three situations — a compliance regime that requires 'no runtime code injection' as a stated control; a multi-tenant host where operators have broad process privileges but should not have an easy path to customer data in live memory; and a hardened image where the smallest possible surface is a design goal in its own right. The controls that actually carry the load sit below the interpreter: user separation, the platform's tracing policy, dropped container capabilities, and who can obtain a shell where the process runs. ### Observability of attaches On the attaching side, `sys.remote_exec` raises the auditing event `sys.remote_exec` with the pid and the script path, so tooling that installs a hook via `sys.addaudithook` can record every attach it performs. That gives you a trail for your own tools and your own operators; it is not a defence against someone running an interpreter you do not control, which is another reason the operating-system boundary is the one that counts. ### A workable policy Decide once, per image, and make it visible: either the build supports attaching and you gate its use, or the build does not and you have accepted that a live process cannot be inspected this way. What you should avoid is the middle state — a fleet where nobody knows which processes are attachable, because the environment variable is set in some manifests and misspelled in others.
- You set PYTHON_DISABLE_REMOTE_DEBUG in your own shell and can still attach. Why?Because the variable is read by the process you are attaching to, at its startup, not by the tool doing the attaching. It has to be in the target's environment — its container spec, service unit or process manager — and the target has to be restarted for it to take effect.
- The operating system already gates who can write another process's memory. Why bother with the switch at all?For defence in depth and for a statement you can audit. The permission is the real boundary, but removing the interpreter's own injection channel means an over-privileged operator or a compromised sidecar has no supported, low-friction path into a live process, and 'this image cannot be attached to' becomes a property you can verify at build time.
- How do you verify the setting actually took effect in a running container?Ask the process, not the manifest: `sys.is_remote_debug_enabled()` returns False when any opt-out applied. This matters because CPython accepts unknown interpreter options of this form silently, so an underscored spelling of the option leaves the feature on with no warning anywhere.
saying these in an interview costs you the question
- Sets the variable in the attaching shell, not the target
- Thinks editing os.environ at runtime disables it
- Spells the option with underscores and assumes it applied
- Calls the switch the security boundary rather than the OS
- Assumes disabling it also blocks native debuggers
- Checks for sys.remote_exec existing instead of asking the process